0031704: Visualization - add an interactive object AIS_LightSource representing a...
[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 {
1663   // Default position and dimension of the viewer window.
1664   // Note that left top corner is set to be sufficiently small to have
1665   // window fit in the small screens (actual for remote desktops, see #23003).
1666   // The position corresponds to the window's client area, thus some
1667   // gap is added for window frame to be visible.
1668   Standard_Integer aPxLeft   = 20;
1669   Standard_Integer aPxTop    = 40;
1670   Standard_Integer aPxWidth  = 409;
1671   Standard_Integer aPxHeight = 409;
1672   Standard_Boolean toCreateViewer = Standard_False;
1673   if (!theViewToClone.IsNull())
1674   {
1675     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1676   }
1677
1678   Handle(OpenGl_GraphicDriver) aGraphicDriver;
1679   ViewerTest_Names aViewNames(theViewName);
1680   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
1681     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1682
1683   if (thePxLeft != 0)
1684     aPxLeft = thePxLeft;
1685   if (thePxTop != 0)
1686     aPxTop = thePxTop;
1687   if (thePxWidth != 0)
1688     aPxWidth = thePxWidth;
1689   if (thePxHeight != 0)
1690     aPxHeight = thePxHeight;
1691
1692   // Get graphic driver (create it or get from another view)
1693   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1694   if (isNewDriver)
1695   {
1696     // Get connection string
1697   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1698     if (!theDisplayName.IsEmpty())
1699     {
1700       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1701     }
1702     else
1703     {
1704       ::Display* aDispX = NULL;
1705       // create dedicated display connection instead of reusing Tk connection
1706       // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
1707       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1708       Tcl_Interp* aTclInterp = aCommands.Interp();
1709       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1710       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1711       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1712     }
1713   #else
1714     (void)theDisplayName; // avoid warning on unused argument
1715     SetDisplayConnection (new Aspect_DisplayConnection ());
1716   #endif
1717
1718     if (Draw_VirtualWindows)
1719     {
1720       // don't waste the time waiting for VSync when window is not displayed on the screen
1721       ViewerTest_myDefaultCaps.swapInterval = 0;
1722       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
1723       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
1724     }
1725     aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection(), false);
1726     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
1727     aGraphicDriver->InitContext();
1728
1729     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1730     toCreateViewer = Standard_True;
1731   }
1732   else
1733   {
1734     aGraphicDriver = Handle(OpenGl_GraphicDriver)::DownCast (ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName()));
1735   }
1736
1737   //Dispose the window if input parameters are default
1738   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1739   {
1740     Standard_Integer aTop = 0,
1741                      aLeft = 0,
1742                      aRight = 0,
1743                      aBottom = 0,
1744                      aScreenWidth = 0,
1745                      aScreenHeight = 0;
1746
1747     // Get screen resolution
1748 #if defined(_WIN32) || defined(__WIN32__)
1749     RECT aWindowSize;
1750     GetClientRect(GetDesktopWindow(), &aWindowSize);
1751     aScreenHeight = aWindowSize.bottom;
1752     aScreenWidth = aWindowSize.right;
1753 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1754     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1755 #else
1756     Screen *aScreen = DefaultScreenOfDisplay(GetDisplayConnection()->GetDisplay());
1757     aScreenWidth = WidthOfScreen(aScreen);
1758     aScreenHeight = HeightOfScreen(aScreen);
1759 #endif
1760
1761     TCollection_AsciiString anOverlappedViewId("");
1762
1763     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1764     {
1765       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1766
1767       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1768         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1769       {
1770         if (aBottom + aPxHeight + 40 > aScreenHeight)
1771         {
1772           aPxLeft = 20;
1773           aPxTop = 40;
1774           break;
1775         }
1776         aPxLeft = 20;
1777         aPxTop = aBottom + 40;
1778       }
1779       else
1780         aPxLeft = aRight + 20;
1781     }
1782   }
1783
1784   // Get viewer name
1785   TCollection_AsciiString aTitle("3D View - ");
1786   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1787
1788   // Change name of current active window
1789   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1790   {
1791     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1792   }
1793
1794   // Create viewer
1795   Handle(V3d_Viewer) a3DViewer;
1796   // If it's the single view, we first look for empty context
1797   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1798   {
1799     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1800       anIter(ViewerTest_myContexts);
1801     if (anIter.More())
1802       ViewerTest::SetAISContext (anIter.Value());
1803     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1804   }
1805   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1806   {
1807     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1808     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1809   }
1810   else if (a3DViewer.IsNull())
1811   {
1812     toCreateViewer = Standard_True;
1813     a3DViewer = new V3d_Viewer(aGraphicDriver);
1814     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1815     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1816                                            ViewerTest_DefaultBackground.GradientColor2,
1817                                            ViewerTest_DefaultBackground.FillMethod);
1818   }
1819
1820   // AIS context setup
1821   if (ViewerTest::GetAISContext().IsNull() ||
1822       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1823   {
1824     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1825     ViewerTest::SetAISContext (aContext);
1826     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1827   }
1828   else
1829   {
1830     ViewerTest::ResetEventManager();
1831   }
1832
1833   // Create window
1834 #if defined(_WIN32)
1835   VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
1836                                     Draw_VirtualWindows ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1837                                     aPxLeft, aPxTop,
1838                                     aPxWidth, aPxHeight,
1839                                     Quantity_NOC_BLACK);
1840   VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
1841 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1842   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1843                                      aPxLeft, aPxTop,
1844                                      aPxWidth, aPxHeight);
1845   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1846 #else
1847   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1848                                   aTitle.ToCString(),
1849                                   aPxLeft, aPxTop,
1850                                   aPxWidth, aPxHeight);
1851 #endif
1852   VT_GetWindow()->SetVirtual (Draw_VirtualWindows);
1853
1854   // View setup
1855   Handle(V3d_View) aView;
1856   if (!theViewToClone.IsNull())
1857   {
1858     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1859   }
1860   else
1861   {
1862     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1863   }
1864
1865   aView->SetWindow (VT_GetWindow());
1866   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1867
1868   ViewerTest::CurrentView(aView);
1869   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1870
1871   // Setup for X11 or NT
1872   OSWindowSetup();
1873
1874   // Set parameters for V3d_View and V3d_Viewer
1875   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1876   aV3dView->SetComputedMode(Standard_False);
1877
1878   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1879   if (toCreateViewer)
1880   {
1881     a3DViewer->SetDefaultLights();
1882     a3DViewer->SetLightOn();
1883   }
1884
1885 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1886   if (isNewDriver)
1887   {
1888     ::Display* aDispX = GetDisplayConnection()->GetDisplay();
1889     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1890   }
1891 #endif
1892
1893   VT_GetWindow()->Map();
1894
1895   // Set the handle of created view in the event manager
1896   ViewerTest::ResetEventManager();
1897
1898   ViewerTest::CurrentView()->Redraw();
1899
1900   aView.Nullify();
1901   a3DViewer.Nullify();
1902
1903   return aViewNames.GetViewName();
1904 }
1905
1906 //==============================================================================
1907 //function : RedrawAllViews
1908 //purpose  : Redraw all created views
1909 //==============================================================================
1910 void ViewerTest::RedrawAllViews()
1911 {
1912   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1913   for (; aViewIt.More(); aViewIt.Next())
1914   {
1915     const Handle(V3d_View)& aView = aViewIt.Key2();
1916     aView->Redraw();
1917   }
1918 }
1919
1920 //==============================================================================
1921 //function : Vinit
1922 //purpose  : Create the window viewer and initialize all the global variable
1923 //    Use Tk_CreateFileHandler on UNIX to catch the X11 Viewer event
1924 //==============================================================================
1925
1926 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1927 {
1928   TCollection_AsciiString aViewName, aDisplayName;
1929   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
1930   Handle(V3d_View) aCopyFrom;
1931   TCollection_AsciiString aName, aValue;
1932   int is2dMode = -1;
1933   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
1934   {
1935     const TCollection_AsciiString anArg = theArgVec[anArgIt];
1936     TCollection_AsciiString anArgCase = anArg;
1937     anArgCase.LowerCase();
1938     if (anArgIt + 1 < theArgsNb
1939      && anArgCase == "-name")
1940     {
1941       aViewName = theArgVec[++anArgIt];
1942     }
1943     else if (anArgIt + 1 < theArgsNb
1944           && (anArgCase == "-left"
1945            || anArgCase == "-l"))
1946     {
1947       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
1948     }
1949     else if (anArgIt + 1 < theArgsNb
1950           && (anArgCase == "-top"
1951            || anArgCase == "-t"))
1952     {
1953       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
1954     }
1955     else if (anArgIt + 1 < theArgsNb
1956           && (anArgCase == "-width"
1957            || anArgCase == "-w"))
1958     {
1959       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
1960     }
1961     else if (anArgIt + 1 < theArgsNb
1962           && (anArgCase == "-height"
1963            || anArgCase == "-h"))
1964     {
1965       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
1966     }
1967     else if (anArgCase == "-exitonclose")
1968     {
1969       ViewerTest_EventManager::ToExitOnCloseView() = true;
1970       if (anArgIt + 1 < theArgsNb
1971        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
1972       {
1973         ++anArgIt;
1974       }
1975     }
1976     else if (anArgCase == "-closeonescape"
1977           || anArgCase == "-closeonesc")
1978     {
1979       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
1980       if (anArgIt + 1 < theArgsNb
1981        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
1982       {
1983         ++anArgIt;
1984       }
1985     }
1986     else if (anArgCase == "-2d_mode"
1987           || anArgCase == "-2dmode"
1988           || anArgCase == "-2d")
1989     {
1990       bool toEnable = true;
1991       if (anArgIt + 1 < theArgsNb
1992        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
1993       {
1994         ++anArgIt;
1995       }
1996       is2dMode = toEnable ? 1 : 0;
1997     }
1998     else if (anArgIt + 1 < theArgsNb
1999           && (anArgCase == "-disp"
2000            || anArgCase == "-display"))
2001     {
2002       aDisplayName = theArgVec[++anArgIt];
2003     }
2004     else if (!ViewerTest::CurrentView().IsNull()
2005           &&  aCopyFrom.IsNull()
2006           && (anArgCase == "-copy"
2007            || anArgCase == "-clone"
2008            || anArgCase == "-cloneactive"
2009            || anArgCase == "-cloneactiveview"))
2010     {
2011       aCopyFrom = ViewerTest::CurrentView();
2012     }
2013     // old syntax
2014     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
2015     {
2016       aName.LowerCase();
2017       if (aName == "name")
2018       {
2019         aViewName = aValue;
2020       }
2021       else if (aName == "l"
2022             || aName == "left")
2023       {
2024         aPxLeft = aValue.IntegerValue();
2025       }
2026       else if (aName == "t"
2027             || aName == "top")
2028       {
2029         aPxTop = aValue.IntegerValue();
2030       }
2031       else if (aName == "disp"
2032             || aName == "display")
2033       {
2034         aDisplayName = aValue;
2035       }
2036       else if (aName == "w"
2037             || aName == "width")
2038       {
2039         aPxWidth = aValue.IntegerValue();
2040       }
2041       else if (aName == "h"
2042             || aName == "height")
2043       {
2044         aPxHeight = aValue.IntegerValue();
2045       }
2046       else
2047       {
2048         Message::SendFail() << "Syntax error: unknown argument " << anArg;
2049         return 1;
2050       }
2051     }
2052     else if (aViewName.IsEmpty())
2053     {
2054       aViewName = anArg;
2055     }
2056     else
2057     {
2058       Message::SendFail() << "Syntax error: unknown argument " << anArg;
2059       return 1;
2060     }
2061   }
2062
2063 #if defined(_WIN32) || (defined(__APPLE__) && !defined(MACOSX_USE_GLX))
2064   if (!aDisplayName.IsEmpty())
2065   {
2066     aDisplayName.Clear();
2067     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
2068   }
2069 #endif
2070
2071   ViewerTest_Names aViewNames (aViewName);
2072   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2073   {
2074     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2075     theDi.Eval (aCommand.ToCString());
2076     if (is2dMode != -1)
2077     {
2078       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2079     }
2080     return 0;
2081   }
2082
2083   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2084                                                             aViewName, aDisplayName, aCopyFrom);
2085   if (is2dMode != -1)
2086   {
2087     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2088   }
2089   theDi << aViewId;
2090   return 0;
2091 }
2092
2093 //! Parse HLR algo type.
2094 static Standard_Boolean parseHlrAlgoType (const char* theName,
2095                                           Prs3d_TypeOfHLR& theType)
2096 {
2097   TCollection_AsciiString aName (theName);
2098   aName.LowerCase();
2099   if (aName == "polyalgo")
2100   {
2101     theType = Prs3d_TOH_PolyAlgo;
2102   }
2103   else if (aName == "algo")
2104   {
2105     theType = Prs3d_TOH_Algo;
2106   }
2107   else
2108   {
2109     return Standard_False;
2110   }
2111   return Standard_True;
2112 }
2113
2114 //==============================================================================
2115 //function : VHLR
2116 //purpose  : hidden lines removal algorithm
2117 //==============================================================================
2118
2119 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2120 {
2121   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2122   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2123   if (aView.IsNull())
2124   {
2125     Message::SendFail ("Error: no active viewer");
2126     return 1;
2127   }
2128
2129   Standard_Boolean hasHlrOnArg = Standard_False;
2130   Standard_Boolean hasShowHiddenArg = Standard_False;
2131   Standard_Boolean isHLROn = Standard_False;
2132   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2133   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2134   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2135   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2136   {
2137     TCollection_AsciiString anArg (argv[anArgIter]);
2138     anArg.LowerCase();
2139     if (anUpdateTool.parseRedrawMode (anArg))
2140     {
2141       continue;
2142     }
2143     else if (anArg == "-showhidden"
2144           && anArgIter + 1 < argc
2145           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2146     {
2147       ++anArgIter;
2148       hasShowHiddenArg = Standard_True;
2149       continue;
2150     }
2151     else if ((anArg == "-type"
2152            || anArg == "-algo"
2153            || anArg == "-algotype")
2154           && anArgIter + 1 < argc
2155           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2156     {
2157       ++anArgIter;
2158       continue;
2159     }
2160     else if (!hasHlrOnArg
2161           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
2162     {
2163       hasHlrOnArg = Standard_True;
2164       continue;
2165     }
2166     // old syntax
2167     else if (!hasShowHiddenArg
2168           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
2169     {
2170       hasShowHiddenArg = Standard_True;
2171       continue;
2172     }
2173     else
2174     {
2175       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
2176       return 1;
2177     }
2178   }
2179   if (!hasHlrOnArg)
2180   {
2181     di << "HLR:        " << aView->ComputedMode() << "\n";
2182     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2183     di << "HlrAlgo:    ";
2184     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2185     {
2186       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2187       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2188       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2189     }
2190     anUpdateTool.Invalidate();
2191     return 0;
2192   }
2193
2194   Standard_Boolean toRecompute = Standard_False;
2195   if (aTypeOfHLR != Prs3d_TOH_NotSet
2196    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2197   {
2198     toRecompute = Standard_True;
2199     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2200   }
2201   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2202   {
2203     toRecompute = Standard_True;
2204     if (toShowHidden)
2205     {
2206       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2207     }
2208     else
2209     {
2210       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2211     }
2212   }
2213
2214   // redisplay shapes
2215   if (aView->ComputedMode() && isHLROn && toRecompute)
2216   {
2217     AIS_ListOfInteractive aListOfShapes;
2218     aCtx->DisplayedObjects (aListOfShapes);
2219     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2220     {
2221       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2222       {
2223         aCtx->Redisplay (aShape, Standard_False);
2224       }
2225     }
2226   }
2227
2228   aView->SetComputedMode (isHLROn);
2229   return 0;
2230 }
2231
2232 //==============================================================================
2233 //function : VHLRType
2234 //purpose  : change type of using HLR algorithm
2235 //==============================================================================
2236
2237 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2238 {
2239   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2240   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2241   if (aView.IsNull())
2242   {
2243     Message::SendFail ("Error: no active viewer");
2244     return 1;
2245   }
2246
2247   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2248   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2249   AIS_ListOfInteractive aListOfShapes;
2250   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2251   {
2252     TCollection_AsciiString anArg (argv[anArgIter]);
2253     anArg.LowerCase();
2254     if (anUpdateTool.parseRedrawMode (anArg))
2255     {
2256       continue;
2257     }
2258     else if ((anArg == "-type"
2259            || anArg == "-algo"
2260            || anArg == "-algotype")
2261           && anArgIter + 1 < argc
2262           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2263     {
2264       ++anArgIter;
2265       continue;
2266     }
2267     // old syntax
2268     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2269           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2270     {
2271       continue;
2272     }
2273     else
2274     {
2275       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2276       TCollection_AsciiString aName (argv[anArgIter]);
2277       if (!aMap.IsBound2 (aName))
2278       {
2279         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
2280         return 1;
2281       }
2282
2283       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2284       if (aShape.IsNull())
2285       {
2286         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
2287         return 1;
2288       }
2289       aListOfShapes.Append (aShape);
2290       continue;
2291     }
2292   }
2293   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2294   {
2295     Message::SendFail ("Syntax error: wrong number of arguments");
2296     return 1;
2297   }
2298
2299   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2300   if (isGlobal)
2301   {
2302     aCtx->DisplayedObjects (aListOfShapes);
2303     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2304   }
2305
2306   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2307   {
2308     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2309     if (aShape.IsNull())
2310     {
2311       continue;
2312     }
2313
2314     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2315                             && aView->ComputedMode();
2316     if (!isGlobal
2317      || aShape->TypeOfHLR() != aTypeOfHLR)
2318     {
2319       aShape->SetTypeOfHLR (aTypeOfHLR);
2320     }
2321     if (toUpdateShape)
2322     {
2323       aCtx->Redisplay (aShape, Standard_False);
2324     }
2325   }
2326   return 0;
2327 }
2328
2329 //==============================================================================
2330 //function : FindViewIdByWindowHandle
2331 //purpose  : Find theView Id in the map of views by window handle
2332 //==============================================================================
2333 #if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2334 TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2335 {
2336   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2337        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2338   {
2339     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2340     if (aWindowHandle == theWindowHandle)
2341       return anIter.Key1();
2342   }
2343   return TCollection_AsciiString("");
2344 }
2345 #endif
2346
2347 //! Make the view active
2348 void ActivateView (const TCollection_AsciiString& theViewName,
2349                    Standard_Boolean theToUpdate = Standard_True)
2350 {
2351   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2352   if (aView.IsNull())
2353   {
2354     return;
2355   }
2356
2357   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2358   if (!anAISContext.IsNull())
2359   {
2360     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2361     {
2362       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2363     }
2364
2365     ViewerTest::CurrentView (aView);
2366     ViewerTest::SetAISContext (anAISContext);
2367     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2368 #if defined(_WIN32)
2369     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
2370 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
2371     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
2372 #else
2373     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
2374 #endif
2375     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2376     if (theToUpdate)
2377     {
2378       ViewerTest::CurrentView()->Redraw();
2379     }
2380   }
2381 }
2382
2383 //==============================================================================
2384 //function : RemoveView
2385 //purpose  :
2386 //==============================================================================
2387 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2388                              const Standard_Boolean  theToRemoveContext)
2389 {
2390   if (!ViewerTest_myViews.IsBound2 (theView))
2391   {
2392     return;
2393   }
2394
2395   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2396   RemoveView (aViewName, theToRemoveContext);
2397 }
2398
2399 //==============================================================================
2400 //function : RemoveView
2401 //purpose  : Close and remove view from display, clear maps if necessary
2402 //==============================================================================
2403 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2404 {
2405   if (!ViewerTest_myViews.IsBound1(theViewName))
2406   {
2407     Message::SendFail() << "Wrong view name";
2408     return;
2409   }
2410
2411   // Activate another view if it's active now
2412   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2413   {
2414     if (ViewerTest_myViews.Extent() > 1)
2415     {
2416       TCollection_AsciiString aNewViewName;
2417       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2418            anIter.More(); anIter.Next())
2419       {
2420         if (anIter.Key1() != theViewName)
2421         {
2422           aNewViewName = anIter.Key1();
2423           break;
2424         }
2425       }
2426       ActivateView (aNewViewName);
2427     }
2428     else
2429     {
2430       VT_GetWindow().Nullify();
2431       ViewerTest::CurrentView (Handle(V3d_View)());
2432       if (isContextRemoved)
2433       {
2434         Handle(AIS_InteractiveContext) anEmptyContext;
2435         ViewerTest::SetAISContext(anEmptyContext);
2436       }
2437     }
2438   }
2439
2440   // Delete view
2441   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2442   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2443   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2444   aRedrawer.Stop (aView->Window());
2445
2446   // Remove view resources
2447   ViewerTest_myViews.UnBind1(theViewName);
2448   aView->Window()->Unmap();
2449   aView->Remove();
2450
2451 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2452   XFlush (GetDisplayConnection()->GetDisplay());
2453 #endif
2454
2455   // Keep context opened only if the closed view is last to avoid
2456   // unused empty contexts
2457   if (!aCurrentContext.IsNull())
2458   {
2459     // Check if there are more difined views in the viewer
2460     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
2461      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
2462     {
2463       // Remove driver if there is no viewers that use it
2464       Standard_Boolean isRemoveDriver = Standard_True;
2465       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2466           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2467       {
2468         if (aCurrentContext != anIter.Key2() &&
2469           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2470         {
2471           isRemoveDriver = Standard_False;
2472           break;
2473         }
2474       }
2475
2476       aCurrentContext->RemoveAll (Standard_False);
2477       if(isRemoveDriver)
2478       {
2479         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2480       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2481         Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
2482       #endif
2483       }
2484
2485       ViewerTest_myContexts.UnBind2(aCurrentContext);
2486     }
2487   }
2488   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
2489   if (ViewerTest_EventManager::ToExitOnCloseView())
2490   {
2491     Draw_Interprete ("exit");
2492   }
2493 }
2494
2495 //==============================================================================
2496 //function : VClose
2497 //purpose  : Remove the view defined by its name
2498 //==============================================================================
2499
2500 static int VClose (Draw_Interpretor& /*theDi*/,
2501                    Standard_Integer  theArgsNb,
2502                    const char**      theArgVec)
2503 {
2504   NCollection_List<TCollection_AsciiString> aViewList;
2505   if (theArgsNb > 1)
2506   {
2507     TCollection_AsciiString anArg (theArgVec[1]);
2508     anArg.UpperCase();
2509     if (anArg.IsEqual ("ALL")
2510      || anArg.IsEqual ("*"))
2511     {
2512       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2513            anIter.More(); anIter.Next())
2514       {
2515         aViewList.Append (anIter.Key1());
2516       }
2517       if (aViewList.IsEmpty())
2518       {
2519         std::cout << "No view to close\n";
2520         return 0;
2521       }
2522     }
2523     else
2524     {
2525       ViewerTest_Names aViewName (theArgVec[1]);
2526       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2527       {
2528         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
2529         return 1;
2530       }
2531       aViewList.Append (aViewName.GetViewName());
2532     }
2533   }
2534   else
2535   {
2536     // close active view
2537     if (ViewerTest::CurrentView().IsNull())
2538     {
2539       Message::SendFail ("Error: no active view");
2540       return 1;
2541     }
2542     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2543   }
2544
2545   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2546   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2547        anIter.More(); anIter.Next())
2548   {
2549     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2550   }
2551
2552   return 0;
2553 }
2554
2555 //==============================================================================
2556 //function : VActivate
2557 //purpose  : Activate the view defined by its ID
2558 //==============================================================================
2559
2560 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2561 {
2562   if (theArgsNb == 1)
2563   {
2564     theDi.Eval("vviewlist");
2565     return 0;
2566   }
2567
2568   TCollection_AsciiString aNameString;
2569   Standard_Boolean toUpdate = Standard_True;
2570   Standard_Boolean toActivate = Standard_True;
2571   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2572   {
2573     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2574     anArg.LowerCase();
2575     if (toUpdate
2576      && anArg == "-noupdate")
2577     {
2578       toUpdate = Standard_False;
2579     }
2580     else if (toActivate
2581           && aNameString.IsEmpty()
2582           && anArg == "none")
2583     {
2584       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2585       VT_GetWindow().Nullify();
2586       ViewerTest::CurrentView (Handle(V3d_View)());
2587       ViewerTest::ResetEventManager();
2588       theDi << theArgVec[0] << ": all views are inactive\n";
2589       toActivate = Standard_False;
2590     }
2591     else if (toActivate
2592           && aNameString.IsEmpty())
2593     {
2594       aNameString = theArgVec[anArgIter];
2595     }
2596     else
2597     {
2598       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2599       return 1;
2600     }
2601   }
2602
2603   if (!toActivate)
2604   {
2605     return 0;
2606   }
2607   else if (aNameString.IsEmpty())
2608   {
2609     Message::SendFail ("Syntax error: wrong number of arguments");
2610     return 1;
2611   }
2612
2613   // Check if this view exists in the viewer with the driver
2614   ViewerTest_Names aViewNames (aNameString);
2615   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2616   {
2617     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2618     return 1;
2619   }
2620
2621   // Check if it is active already
2622   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2623   {
2624     theDi << theArgVec[0] << ": the view is active already\n";
2625     return 0;
2626   }
2627
2628   ActivateView (aViewNames.GetViewName(), toUpdate);
2629   return 0;
2630 }
2631
2632 //==============================================================================
2633 //function : VViewList
2634 //purpose  : Print current list of views per viewer and graphic driver ID
2635 //           shared between viewers
2636 //==============================================================================
2637
2638 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2639 {
2640   if (theArgsNb > 2)
2641   {
2642     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2643           << "Usage: " << theArgVec[0] << " name";
2644     return 1;
2645   }
2646   if (ViewerTest_myContexts.Size() < 1)
2647     return 0;
2648
2649   Standard_Boolean isTreeView =
2650     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2651
2652   if (isTreeView)
2653   {
2654     theDi << theArgVec[0] <<":\n";
2655   }
2656
2657   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2658        aDriverIter.More(); aDriverIter.Next())
2659   {
2660     if (isTreeView)
2661       theDi << aDriverIter.Key1() << ":\n";
2662
2663     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2664       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2665     {
2666       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2667       {
2668         if (isTreeView)
2669         {
2670           TCollection_AsciiString aContextName(aContextIter.Key1());
2671           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2672         }
2673
2674         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2675              aViewIter.More(); aViewIter.Next())
2676         {
2677           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2678           {
2679             TCollection_AsciiString aViewName(aViewIter.Key1());
2680             if (isTreeView)
2681             {
2682               if (aViewIter.Value() == ViewerTest::CurrentView())
2683                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2684               else
2685                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2686             }
2687             else
2688             {
2689               theDi << aViewName << " ";
2690             }
2691           }
2692         }
2693       }
2694     }
2695   }
2696   return 0;
2697 }
2698
2699 //==============================================================================
2700 //function : GetMousePosition
2701 //purpose  :
2702 //==============================================================================
2703 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2704                                    Standard_Integer& theY)
2705 {
2706   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2707   {
2708     theX = aViewCtrl->LastMousePosition().x();
2709     theY = aViewCtrl->LastMousePosition().y();
2710   }
2711 }
2712
2713 //==============================================================================
2714 //function : VViewProj
2715 //purpose  : Switch view projection
2716 //==============================================================================
2717 static int VViewProj (Draw_Interpretor& ,
2718                       Standard_Integer theNbArgs,
2719                       const char** theArgVec)
2720 {
2721   static Standard_Boolean isYup = Standard_False;
2722   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2723   if (aView.IsNull())
2724   {
2725     Message::SendFail ("Error: no active viewer");
2726     return 1;
2727   }
2728
2729   TCollection_AsciiString aCmdName (theArgVec[0]);
2730   Standard_Boolean isGeneralCmd = Standard_False;
2731   if (aCmdName == "vfront")
2732   {
2733     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2734   }
2735   else if (aCmdName == "vback")
2736   {
2737     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2738   }
2739   else if (aCmdName == "vtop")
2740   {
2741     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2742   }
2743   else if (aCmdName == "vbottom")
2744   {
2745     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2746   }
2747   else if (aCmdName == "vleft")
2748   {
2749     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2750   }
2751   else if (aCmdName == "vright")
2752   {
2753     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2754   }
2755   else if (aCmdName == "vaxo")
2756   {
2757     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2758   }
2759   else
2760   {
2761     isGeneralCmd = Standard_True;
2762     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2763     {
2764       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2765       anArgCase.LowerCase();
2766       if (anArgCase == "-zup")
2767       {
2768         isYup = Standard_False;
2769       }
2770       else if (anArgCase == "-yup")
2771       {
2772         isYup = Standard_True;
2773       }
2774       else if (anArgCase == "-front"
2775             || anArgCase == "front"
2776             || anArgCase == "-f"
2777             || anArgCase == "f")
2778       {
2779         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2780       }
2781       else if (anArgCase == "-back"
2782             || anArgCase == "back"
2783             || anArgCase == "-b"
2784             || anArgCase == "b")
2785       {
2786         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2787       }
2788       else if (anArgCase == "-top"
2789             || anArgCase == "top"
2790             || anArgCase == "-t"
2791             || anArgCase == "t")
2792       {
2793         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2794       }
2795       else if (anArgCase == "-bottom"
2796             || anArgCase == "bottom"
2797             || anArgCase == "-bot"
2798             || anArgCase == "bot"
2799             || anArgCase == "-b"
2800             || anArgCase == "b")
2801       {
2802         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2803       }
2804       else if (anArgCase == "-left"
2805             || anArgCase == "left"
2806             || anArgCase == "-l"
2807             || anArgCase == "l")
2808       {
2809         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2810       }
2811       else if (anArgCase == "-right"
2812             || anArgCase == "right"
2813             || anArgCase == "-r"
2814             || anArgCase == "r")
2815       {
2816         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2817       }
2818       else if (anArgCase == "-axoleft"
2819             || anArgCase == "-leftaxo"
2820             || anArgCase == "axoleft"
2821             || anArgCase == "leftaxo")
2822       {
2823         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
2824       }
2825       else if (anArgCase == "-axo"
2826             || anArgCase == "axo"
2827             || anArgCase == "-a"
2828             || anArgCase == "a"
2829             || anArgCase == "-axoright"
2830             || anArgCase == "-rightaxo"
2831             || anArgCase == "axoright"
2832             || anArgCase == "rightaxo")
2833       {
2834         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2835       }
2836       else if (anArgCase == "+x")
2837       {
2838         aView->SetProj (V3d_Xpos, isYup);
2839       }
2840       else if (anArgCase == "-x")
2841       {
2842         aView->SetProj (V3d_Xneg, isYup);
2843       }
2844       else if (anArgCase == "+y")
2845       {
2846         aView->SetProj (V3d_Ypos, isYup);
2847       }
2848       else if (anArgCase == "-y")
2849       {
2850         aView->SetProj (V3d_Yneg, isYup);
2851       }
2852       else if (anArgCase == "+z")
2853       {
2854         aView->SetProj (V3d_Zpos, isYup);
2855       }
2856       else if (anArgCase == "-z")
2857       {
2858         aView->SetProj (V3d_Zneg, isYup);
2859       }
2860       else if (anArgCase == "+x+y+z")
2861       {
2862         aView->SetProj (V3d_XposYposZpos, isYup);
2863       }
2864       else if (anArgCase == "+x+y-z")
2865       {
2866         aView->SetProj (V3d_XposYposZneg, isYup);
2867       }
2868       else if (anArgCase == "+x-y+z")
2869       {
2870         aView->SetProj (V3d_XposYnegZpos, isYup);
2871       }
2872       else if (anArgCase == "+x-y-z")
2873       {
2874         aView->SetProj (V3d_XposYnegZneg, isYup);
2875       }
2876       else if (anArgCase == "-x+y+z")
2877       {
2878         aView->SetProj (V3d_XnegYposZpos, isYup);
2879       }
2880       else if (anArgCase == "-x+y-z")
2881       {
2882         aView->SetProj (V3d_XnegYposZneg, isYup);
2883       }
2884       else if (anArgCase == "-x-y+z")
2885       {
2886         aView->SetProj (V3d_XnegYnegZpos, isYup);
2887       }
2888       else if (anArgCase == "-x-y-z")
2889       {
2890         aView->SetProj (V3d_XnegYnegZneg, isYup);
2891       }
2892       else if (anArgCase == "+x+y")
2893       {
2894         aView->SetProj (V3d_XposYpos, isYup);
2895       }
2896       else if (anArgCase == "+x-y")
2897       {
2898         aView->SetProj (V3d_XposYneg, isYup);
2899       }
2900       else if (anArgCase == "-x+y")
2901       {
2902         aView->SetProj (V3d_XnegYpos, isYup);
2903       }
2904       else if (anArgCase == "-x-y")
2905       {
2906         aView->SetProj (V3d_XnegYneg, isYup);
2907       }
2908       else if (anArgCase == "+x+z")
2909       {
2910         aView->SetProj (V3d_XposZpos, isYup);
2911       }
2912       else if (anArgCase == "+x-z")
2913       {
2914         aView->SetProj (V3d_XposZneg, isYup);
2915       }
2916       else if (anArgCase == "-x+z")
2917       {
2918         aView->SetProj (V3d_XnegZpos, isYup);
2919       }
2920       else if (anArgCase == "-x-z")
2921       {
2922         aView->SetProj (V3d_XnegZneg, isYup);
2923       }
2924       else if (anArgCase == "+y+z")
2925       {
2926         aView->SetProj (V3d_YposZpos, isYup);
2927       }
2928       else if (anArgCase == "+y-z")
2929       {
2930         aView->SetProj (V3d_YposZneg, isYup);
2931       }
2932       else if (anArgCase == "-y+z")
2933       {
2934         aView->SetProj (V3d_YnegZpos, isYup);
2935       }
2936       else if (anArgCase == "-y-z")
2937       {
2938         aView->SetProj (V3d_YnegZneg, isYup);
2939       }
2940       else if (anArgIter + 1 < theNbArgs
2941             && anArgCase == "-frame"
2942             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
2943       {
2944         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
2945         aFrameDef.LowerCase();
2946         gp_Dir aRight, anUp;
2947         if (aFrameDef.Value (2) == aFrameDef.Value (4))
2948         {
2949           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2950           return 1;
2951         }
2952
2953         if (aFrameDef.Value (2) == 'x')
2954         {
2955           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
2956         }
2957         else if (aFrameDef.Value (2) == 'y')
2958         {
2959           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
2960         }
2961         else if (aFrameDef.Value (2) == 'z')
2962         {
2963           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
2964         }
2965         else
2966         {
2967           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2968           return 1;
2969         }
2970
2971         if (aFrameDef.Value (4) == 'x')
2972         {
2973           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
2974         }
2975         else if (aFrameDef.Value (4) == 'y')
2976         {
2977           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
2978         }
2979         else if (aFrameDef.Value (4) == 'z')
2980         {
2981           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
2982         }
2983         else
2984         {
2985           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2986           return 1;
2987         }
2988
2989         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
2990         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
2991         const gp_Dir aDir = anUp.Crossed (aRight);
2992         aCamera->SetCenter (gp_Pnt (0, 0, 0));
2993         aCamera->SetDirection (aDir);
2994         aCamera->SetUp (anUp);
2995         aCamera->OrthogonalizeUp();
2996
2997         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
2998         aView->Update();
2999       }
3000       else
3001       {
3002         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3003         return 1;
3004       }
3005     }
3006   }
3007
3008   if (!isGeneralCmd
3009     && theNbArgs != 1)
3010   {
3011     Message::SendFail ("Syntax error: wrong number of arguments");
3012     return 1;
3013   }
3014   return 0;
3015 }
3016
3017 //==============================================================================
3018 //function : VHelp
3019 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
3020 //Draw arg : No args
3021 //==============================================================================
3022
3023 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
3024 {
3025   di << "=========================\n";
3026   di << "F : FitAll\n";
3027   di << "T : TopView\n";
3028   di << "B : BottomView\n";
3029   di << "R : RightView\n";
3030   di << "L : LeftView\n";
3031   di << "Backspace : AxonometricView\n";
3032
3033   di << "=========================\n";
3034   di << "W, S : Fly   forward/backward\n";
3035   di << "A, D : Slide left/right\n";
3036   di << "Q, E : Bank  left/right\n";
3037   di << "-, + : Change flying speed\n";
3038   di << "Arrows : look left/right/up/down\n";
3039   di << "Arrows+Shift : slide left/right/up/down\n";
3040
3041   di << "=========================\n";
3042   di << "S + Ctrl : Shading\n";
3043   di << "W + Ctrl : Wireframe\n";
3044   di << "H : HiddenLineRemoval\n";
3045   di << "U : Unset display mode\n";
3046   di << "Delete : Remove selection from viewer\n";
3047
3048   di << "=========================\n";
3049   di << "Selection mode \n";
3050   di << "0 : Shape\n";
3051   di << "1 : Vertex\n";
3052   di << "2 : Edge\n";
3053   di << "3 : Wire\n";
3054   di << "4 : Face\n";
3055   di << "5 : Shell\n";
3056   di << "6 : Solid\n";
3057   di << "7 : Compound\n";
3058
3059   di << "=========================\n";
3060   di << "< : Hilight next detected\n";
3061   di << "> : Hilight previous detected\n";
3062
3063   return 0;
3064 }
3065
3066 #ifdef _WIN32
3067
3068 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
3069                                            UINT theMsg,
3070                                            WPARAM wParam,
3071                                            LPARAM lParam )
3072 {
3073   if (ViewerTest_myViews.IsEmpty())
3074   {
3075     return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3076   }
3077
3078   switch (theMsg)
3079   {
3080     case WM_CLOSE:
3081     {
3082       // Delete view from map of views
3083       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3084       return 0;
3085     }
3086     case WM_ACTIVATE:
3087     {
3088       if (LOWORD(wParam) == WA_CLICKACTIVE
3089        || LOWORD(wParam) == WA_ACTIVE
3090        || ViewerTest::CurrentView().IsNull())
3091       {
3092         // Activate inactive window
3093         if (VT_GetWindow().IsNull()
3094          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3095         {
3096           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3097         }
3098       }
3099       break;
3100     }
3101     default:
3102     {
3103       return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3104     }
3105   }
3106   return 0;
3107 }
3108
3109 static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle,
3110                                         UINT theMsg,
3111                                         WPARAM wParam,
3112                                         LPARAM lParam)
3113 {
3114   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3115   if (aView.IsNull())
3116   {
3117     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3118   }
3119
3120   switch (theMsg)
3121   {
3122     case WM_PAINT:
3123     {
3124       PAINTSTRUCT aPaint;
3125       BeginPaint(theWinHandle, &aPaint);
3126       EndPaint  (theWinHandle, &aPaint);
3127       ViewerTest::CurrentEventManager()->ProcessExpose();
3128       break;
3129     }
3130     case WM_SIZE:
3131     {
3132       ViewerTest::CurrentEventManager()->ProcessConfigure();
3133       break;
3134     }
3135     case WM_MOVE:
3136     case WM_MOVING:
3137     case WM_SIZING:
3138     {
3139       switch (aView->RenderingParams().StereoMode)
3140       {
3141         case Graphic3d_StereoMode_RowInterlaced:
3142         case Graphic3d_StereoMode_ColumnInterlaced:
3143         case Graphic3d_StereoMode_ChessBoard:
3144         {
3145           // track window moves to reverse stereo pair
3146           aView->MustBeResized();
3147           aView->Update();
3148           break;
3149         }
3150         default:
3151           break;
3152       }
3153       break;
3154     }
3155     case WM_KEYUP:
3156     case WM_KEYDOWN:
3157     {
3158       const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam);
3159       if (aVKey != Aspect_VKey_UNKNOWN)
3160       {
3161         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3162         if (theMsg == WM_KEYDOWN)
3163         {
3164           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3165         }
3166         else
3167         {
3168           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3169         }
3170         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3171       }
3172       break;
3173     }
3174     case WM_LBUTTONUP:
3175     case WM_MBUTTONUP:
3176     case WM_RBUTTONUP:
3177     case WM_LBUTTONDOWN:
3178     case WM_MBUTTONDOWN:
3179     case WM_RBUTTONDOWN:
3180     {
3181       const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3182       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3183       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3184       switch (theMsg)
3185       {
3186         case WM_LBUTTONUP:
3187         case WM_LBUTTONDOWN:
3188           aButton = Aspect_VKeyMouse_LeftButton;
3189           break;
3190         case WM_MBUTTONUP:
3191         case WM_MBUTTONDOWN:
3192           aButton = Aspect_VKeyMouse_MiddleButton;
3193           break;
3194         case WM_RBUTTONUP:
3195         case WM_RBUTTONDOWN:
3196           aButton = Aspect_VKeyMouse_RightButton;
3197           break;
3198       }
3199       if (theMsg == WM_LBUTTONDOWN
3200        || theMsg == WM_MBUTTONDOWN
3201        || theMsg == WM_RBUTTONDOWN)
3202       {
3203         if (aButton == Aspect_VKeyMouse_LeftButton)
3204         {
3205           TheIsAnimating = Standard_False;
3206         }
3207
3208         SetFocus  (theWinHandle);
3209         SetCapture(theWinHandle);
3210         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3211       }
3212       else
3213       {
3214         ReleaseCapture();
3215         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3216       }
3217       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3218       break;
3219     }
3220     case WM_MOUSEWHEEL:
3221     {
3222       const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
3223       const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
3224       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3225       Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam))));
3226       POINT aCursorPnt = { aPos.x(), aPos.y() };
3227       if (ScreenToClient (theWinHandle, &aCursorPnt))
3228       {
3229         aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3230       }
3231
3232       ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3233       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3234       break;
3235     }
3236     case WM_MOUSEMOVE:
3237     {
3238       Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3239       Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam);
3240       Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(wParam);
3241
3242       // don't make a slide-show from input events - fetch the actual mouse cursor position
3243       CURSORINFO aCursor;
3244       aCursor.cbSize = sizeof(aCursor);
3245       if (::GetCursorInfo (&aCursor) != FALSE)
3246       {
3247         POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
3248         if (ScreenToClient (theWinHandle, &aCursorPnt))
3249         {
3250           // as we override mouse position, we need overriding also mouse state
3251           aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3252           aButtons = WNT_Window::MouseButtonsAsync();
3253           aFlags   = WNT_Window::MouseKeyFlagsAsync();
3254         }
3255       }
3256
3257       if (VT_GetWindow().IsNull()
3258       || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3259       {
3260         // mouse move events come also for inactive windows
3261         break;
3262       }
3263
3264       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3265       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
3266       break;
3267     }
3268     case WM_INPUT:
3269     {
3270       UINT aSize = 0;
3271       ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, NULL, &aSize, sizeof(RAWINPUTHEADER));
3272       NCollection_LocalArray<BYTE> aRawData (aSize);
3273       if (aSize == 0 || ::GetRawInputData ((HRAWINPUT )lParam, RID_INPUT, aRawData, &aSize, sizeof(RAWINPUTHEADER)) != aSize)
3274       {
3275         break;
3276       }
3277
3278       const RAWINPUT* aRawInput = (RAWINPUT* )(BYTE* )aRawData;
3279       if (aRawInput->header.dwType != RIM_TYPEHID)
3280       {
3281         break;
3282       }
3283
3284       RID_DEVICE_INFO aDevInfo;
3285       aDevInfo.cbSize = sizeof(RID_DEVICE_INFO);
3286       UINT aDevInfoSize = sizeof(RID_DEVICE_INFO);
3287       if (::GetRawInputDeviceInfoW (aRawInput->header.hDevice, RIDI_DEVICEINFO, &aDevInfo, &aDevInfoSize) != sizeof(RID_DEVICE_INFO)
3288         || (aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_LOGITECH
3289          && aDevInfo.hid.dwVendorId != WNT_HIDSpaceMouse::VENDOR_ID_3DCONNEXION))
3290       {
3291         break;
3292       }
3293
3294       WNT_HIDSpaceMouse aSpaceData (aDevInfo.hid.dwProductId, aRawInput->data.hid.bRawData, aRawInput->data.hid.dwSizeHid);
3295       if (ViewerTest::CurrentEventManager()->Update3dMouse (aSpaceData)
3296       && !VT_GetWindow().IsNull())
3297       {
3298         VT_GetWindow()->InvalidateContent();
3299       }
3300       break;
3301     }
3302     default:
3303     {
3304       return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3305     }
3306   }
3307   return 0L;
3308 }
3309
3310 //==============================================================================
3311 //function : ViewerMainLoop
3312 //purpose  : Get a Event on the view and dispatch it
3313 //==============================================================================
3314
3315 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3316 {
3317   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3318   if (aViewCtrl.IsNull()
3319    || theNbArgs < 4)
3320   {
3321     return 0;
3322   }
3323
3324   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3325
3326   std::cout << "Start picking\n";
3327
3328   MSG aMsg;
3329   aMsg.wParam = 1;
3330   while (aViewCtrl->ToPickPoint())
3331   {
3332     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3333     if (GetMessageW (&aMsg, NULL, 0, 0))
3334     {
3335       TranslateMessage (&aMsg);
3336       DispatchMessageW (&aMsg);
3337     }
3338   }
3339
3340   std::cout << "Picking done\n";
3341   return 0;
3342 }
3343
3344 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
3345
3346 int min( int a, int b )
3347 {
3348   if( a<b )
3349     return a;
3350   else
3351     return b;
3352 }
3353
3354 int max( int a, int b )
3355 {
3356   if( a>b )
3357     return a;
3358   else
3359     return b;
3360 }
3361
3362 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3363 {
3364   static XEvent aReport;
3365   const Standard_Boolean toPick = theNbArgs > 0;
3366   if (theNbArgs > 0)
3367   {
3368     if (ViewerTest::CurrentEventManager().IsNull())
3369     {
3370       return 0;
3371     }
3372     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3373   }
3374
3375   Display* aDisplay = GetDisplayConnection()->GetDisplay();
3376   XNextEvent (aDisplay, &aReport);
3377
3378   // Handle event for the chosen display connection
3379   switch (aReport.type)
3380   {
3381     case ClientMessage:
3382     {
3383       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3384       {
3385         // Close the window
3386         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3387         return toPick ? 0 : 1;
3388       }
3389       break;
3390     }
3391     case FocusIn:
3392     {
3393       // Activate inactive view
3394       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3395       if (aWindow != aReport.xfocus.window)
3396       {
3397         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3398       }
3399       break;
3400     }
3401     case Expose:
3402     {
3403       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3404       if (anXWindow == aReport.xexpose.window)
3405       {
3406         ViewerTest::CurrentEventManager()->ProcessExpose();
3407       }
3408
3409       // remove all the ExposureMask and process them at once
3410       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3411       {
3412         if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
3413         {
3414           break;
3415         }
3416       }
3417
3418       break;
3419     }
3420     case ConfigureNotify:
3421     {
3422       // remove all the StructureNotifyMask and process them at once
3423       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3424       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3425       {
3426         if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
3427         {
3428           break;
3429         }
3430       }
3431
3432       if (anXWindow == aReport.xconfigure.window)
3433       {
3434         ViewerTest::CurrentEventManager()->ProcessConfigure();
3435       }
3436       break;
3437     }
3438     case KeyPress:
3439     case KeyRelease:
3440     {
3441       XKeyEvent*   aKeyEvent = (XKeyEvent* )&aReport;
3442       const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
3443       const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
3444       if (aVKey != Aspect_VKey_UNKNOWN)
3445       {
3446         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3447         if (aReport.type == KeyPress)
3448         {
3449           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3450         }
3451         else
3452         {
3453           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3454         }
3455         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3456       }
3457       break;
3458     }
3459     case ButtonPress:
3460     case ButtonRelease:
3461     {
3462       const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y);
3463       Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
3464       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3465       if (aReport.xbutton.button == Button1)
3466       {
3467         aButton = Aspect_VKeyMouse_LeftButton;
3468       }
3469       if (aReport.xbutton.button == Button2)
3470       {
3471         aButton = Aspect_VKeyMouse_MiddleButton;
3472       }
3473       if (aReport.xbutton.button == Button3)
3474       {
3475         aButton = Aspect_VKeyMouse_RightButton;
3476       }
3477
3478       if (aReport.xbutton.state & ControlMask)
3479       {
3480         aFlags |= Aspect_VKeyFlags_CTRL;
3481       }
3482       if (aReport.xbutton.state & ShiftMask)
3483       {
3484         aFlags |= Aspect_VKeyFlags_SHIFT;
3485       }
3486       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3487       {
3488         aFlags |= Aspect_VKeyFlags_ALT;
3489       }
3490
3491       if (aReport.xbutton.button == Button4
3492        || aReport.xbutton.button == Button5)
3493       {
3494         if (aReport.type != ButtonPress)
3495         {
3496           break;
3497         }
3498
3499         const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0);
3500         ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3501       }
3502       else if (aReport.type == ButtonPress)
3503       {
3504         if (aButton == Aspect_VKeyMouse_LeftButton)
3505         {
3506           TheIsAnimating = Standard_False;
3507         }
3508         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3509       }
3510       else
3511       {
3512         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3513       }
3514       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3515       break;
3516     }
3517     case MotionNotify:
3518     {
3519       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3520       if (anXWindow != aReport.xmotion.window)
3521       {
3522         break;
3523       }
3524
3525       // remove all the ButtonMotionMask and process them at once
3526       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3527       {
3528         if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport))
3529         {
3530           break;
3531         }
3532       }
3533
3534       Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y);
3535       Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
3536       Aspect_VKeyFlags aFlags   = Aspect_VKeyFlags_NONE;
3537       if ((aReport.xmotion.state & Button1Mask) != 0)
3538       {
3539         aButtons |= Aspect_VKeyMouse_LeftButton;
3540       }
3541       else if ((aReport.xmotion.state & Button2Mask) != 0)
3542       {
3543         aButtons |= Aspect_VKeyMouse_MiddleButton;
3544       }
3545       else if ((aReport.xmotion.state & Button3Mask) != 0)
3546       {
3547         aButtons |= Aspect_VKeyMouse_RightButton;
3548       }
3549
3550       if (aReport.xmotion.state & ControlMask)
3551       {
3552         aFlags |= Aspect_VKeyFlags_CTRL;
3553       }
3554       if (aReport.xmotion.state & ShiftMask)
3555       {
3556         aFlags |= Aspect_VKeyFlags_SHIFT;
3557       }
3558       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3559       {
3560         aFlags |= Aspect_VKeyFlags_ALT;
3561       }
3562
3563       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3564       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3565       break;
3566     }
3567   }
3568   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
3569 }
3570
3571 //==============================================================================
3572 //function : VProcessEvents
3573 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
3574 //==============================================================================
3575 static void VProcessEvents (ClientData theDispX, int)
3576 {
3577   Display* aDispX = (Display* )theDispX;
3578   Handle(Aspect_DisplayConnection) aDispConn;
3579   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
3580        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
3581   {
3582     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
3583     if (aDispConnTmp->GetDisplay() == aDispX)
3584     {
3585       aDispConn = aDispConnTmp;
3586       break;
3587     }
3588   }
3589   if (aDispConn.IsNull())
3590   {
3591     Message::SendFail ("Error: ViewerTest is unable processing messages for unknown X Display");
3592     return;
3593   }
3594
3595   // process new events in queue
3596   SetDisplayConnection (aDispConn);
3597   int aNbRemain = 0;
3598   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
3599   {
3600     const int anEventResult = ViewerMainLoop (0, NULL);
3601     if (anEventResult == 0)
3602     {
3603       return;
3604     }
3605
3606     aNbRemain = XPending (aDispX);
3607     if (++anEventIter >= aNbEventsMax
3608      || aNbRemain <= 0)
3609     {
3610       break;
3611     }
3612   }
3613
3614   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
3615   // it is possible that new events will arrive to queue before the end of this callback
3616   // so that either this callback should go into an infinite loop (blocking processing of other events)
3617   // or to keep unprocessed events till the next queue update (which can arrive not soon).
3618   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
3619   if (aNbRemain != 0)
3620   {
3621     XEvent aDummyEvent;
3622     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
3623     aDummyEvent.type = ClientMessage;
3624     aDummyEvent.xclient.format = 32;
3625     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
3626     XFlush (aDispX);
3627   }
3628
3629   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
3630   {
3631     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
3632   }
3633 }
3634 #endif
3635
3636 //==============================================================================
3637 //function : OSWindowSetup
3638 //purpose  : Setup for the X11 window to be able to cath the event
3639 //==============================================================================
3640
3641
3642 static void OSWindowSetup()
3643 {
3644 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
3645   // X11
3646
3647   Window  window   = VT_GetWindow()->XWindow();
3648   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
3649   Display *aDisplay = GetDisplayConnection()->GetDisplay();
3650   XSynchronize(aDisplay, 1);
3651
3652   // X11 : For keyboard on SUN
3653   XWMHints wmhints;
3654   wmhints.flags = InputHint;
3655   wmhints.input = 1;
3656
3657   XSetWMHints( aDisplay, window, &wmhints);
3658
3659   XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask | KeyReleaseMask |
3660     ButtonPressMask | ButtonReleaseMask |
3661     StructureNotifyMask |
3662     PointerMotionMask |
3663     Button1MotionMask | Button2MotionMask |
3664     Button3MotionMask | FocusChangeMask
3665     );
3666   Atom aDeleteWindowAtom = GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW);
3667   XSetWMProtocols(aDisplay, window, &aDeleteWindowAtom, 1);
3668
3669   XSynchronize(aDisplay, 0);
3670
3671 #else
3672   // _WIN32
3673 #endif
3674
3675 }
3676
3677 //==============================================================================
3678 //function : VFit
3679 //purpose  :
3680 //==============================================================================
3681
3682 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
3683 {
3684   const Handle(V3d_View) aView = ViewerTest::CurrentView();
3685   if (aView.IsNull())
3686   {
3687     Message::SendFail ("Error: no active viewer");
3688     return 1;
3689   }
3690
3691   Standard_Boolean toFit = Standard_True;
3692   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
3693   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3694   {
3695     TCollection_AsciiString anArg (theArgv[anArgIter]);
3696     anArg.LowerCase();
3697     if (anUpdateTool.parseRedrawMode (anArg))
3698     {
3699       continue;
3700     }
3701     else if (anArg == "-selected")
3702     {
3703       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
3704       toFit = Standard_False;
3705     }
3706     else
3707     {
3708       Message::SendFail() << "Syntax error at '" << anArg << "'";
3709     }
3710   }
3711
3712   if (toFit)
3713   {
3714     aView->FitAll (0.01, Standard_False);
3715   }
3716   return 0;
3717 }
3718
3719 //=======================================================================
3720 //function : VFitArea
3721 //purpose  : Fit view to show area located between two points
3722 //         : given in world 2D or 3D coordinates.
3723 //=======================================================================
3724 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
3725 {
3726   Handle(V3d_View) aView = ViewerTest::CurrentView();
3727   if (aView.IsNull())
3728   {
3729     Message::SendFail ("Error: No active viewer");
3730     return 1;
3731   }
3732
3733   // Parse arguments.
3734   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
3735   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
3736
3737   if (theArgNb == 5)
3738   {
3739     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3740     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3741     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
3742     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
3743   }
3744   else if (theArgNb == 7)
3745   {
3746     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3747     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3748     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
3749     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
3750     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
3751     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
3752   }
3753   else
3754   {
3755     Message::SendFail ("Syntax error: Invalid number of arguments");
3756     theDI.PrintHelp(theArgVec[0]);
3757     return 1;
3758   }
3759
3760   // Convert model coordinates to view space
3761   Handle(Graphic3d_Camera) aCamera = aView->Camera();
3762   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
3763   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
3764
3765   // Determine fit area
3766   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
3767   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
3768
3769   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
3770
3771   if (aDiagonal < Precision::Confusion())
3772   {
3773     Message::SendFail ("Error: view area is too small");
3774     return 1;
3775   }
3776
3777   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
3778   return 0;
3779 }
3780
3781 //==============================================================================
3782 //function : VZFit
3783 //purpose  : ZFitall, no DRAW arguments
3784 //Draw arg : No args
3785 //==============================================================================
3786 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
3787 {
3788   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
3789
3790   if (aCurrentView.IsNull())
3791   {
3792     Message::SendFail ("Error: no active viewer");
3793     return 1;
3794   }
3795
3796   if (theArgsNb == 1)
3797   {
3798     aCurrentView->ZFitAll();
3799     aCurrentView->Redraw();
3800     return 0;
3801   }
3802
3803   Standard_Real aScale = 1.0;
3804
3805   if (theArgsNb >= 2)
3806   {
3807     aScale = Draw::Atoi (theArgVec[1]);
3808   }
3809
3810   aCurrentView->ZFitAll (aScale);
3811   aCurrentView->Redraw();
3812
3813   return 0;
3814 }
3815
3816 //==============================================================================
3817 //function : VRepaint
3818 //purpose  :
3819 //==============================================================================
3820 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
3821 {
3822   Handle(V3d_View) aView = ViewerTest::CurrentView();
3823   if (aView.IsNull())
3824   {
3825     Message::SendFail ("Error: no active viewer");
3826     return 1;
3827   }
3828
3829   Standard_Boolean isImmediateUpdate = Standard_False;
3830   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3831   {
3832     TCollection_AsciiString anArg (theArgVec[anArgIter]);
3833     anArg.LowerCase();
3834     if (anArg == "-immediate"
3835      || anArg == "-imm")
3836     {
3837       isImmediateUpdate = Standard_True;
3838       if (anArgIter + 1 < theArgNb
3839        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
3840       {
3841         ++anArgIter;
3842       }
3843     }
3844     else if (anArg == "-continuous"
3845           || anArg == "-cont"
3846           || anArg == "-fps"
3847           || anArg == "-framerate")
3848     {
3849       Standard_Real aFps = -1.0;
3850       if (anArgIter + 1 < theArgNb
3851        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue (Standard_True))
3852       {
3853         aFps = Draw::Atof (theArgVec[++anArgIter]);
3854       }
3855
3856       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
3857       if (Abs (aFps) >= 1.0)
3858       {
3859         aRedrawer.Start (aView->Window(), aFps);
3860       }
3861       else
3862       {
3863         aRedrawer.Stop();
3864       }
3865     }
3866     else
3867     {
3868       Message::SendFail() << "Syntax error at '" << anArg << "'";
3869       return 1;
3870     }
3871   }
3872
3873   if (isImmediateUpdate)
3874   {
3875     aView->RedrawImmediate();
3876   }
3877   else
3878   {
3879     aView->Redraw();
3880   }
3881   return 0;
3882 }
3883
3884 //==============================================================================
3885 //function : VClear
3886 //purpose  : Remove all the object from the viewer
3887 //Draw arg : No args
3888 //==============================================================================
3889
3890 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
3891 {
3892   Handle(V3d_View) V = ViewerTest::CurrentView();
3893   if(!V.IsNull())
3894     ViewerTest::Clear();
3895   return 0;
3896 }
3897
3898 //==============================================================================
3899 //function : VPick
3900 //purpose  :
3901 //==============================================================================
3902
3903 static int VPick (Draw_Interpretor& ,
3904                   Standard_Integer theNbArgs,
3905                   const char** theArgVec)
3906 {
3907   if (ViewerTest::CurrentView().IsNull())
3908   {
3909     return 1;
3910   }
3911
3912   if (theNbArgs < 4)
3913   {
3914     Message::SendFail ("Syntax error: wrong number of arguments");
3915     return 1;
3916   }
3917
3918   while (ViewerMainLoop (theNbArgs, theArgVec))
3919   {
3920     //
3921   }
3922
3923   return 0;
3924 }
3925
3926 namespace
3927 {
3928
3929   //! Changes the background
3930   //! @param theDrawInterpretor the interpreter of the Draw Harness application
3931   //! @param theNumberOfCommandLineArguments the number of passed command line arguments
3932   //! @param theCommandLineArguments the array of command line arguments
3933   //! @return TCL_OK if changing was successful, or TCL_ERROR otherwise
3934   static int vbackground (Draw_Interpretor&      theDrawInterpretor,
3935                           const Standard_Integer theNumberOfCommandLineArguments,
3936                           const char** const     theCommandLineArguments)
3937   {
3938     if (theNumberOfCommandLineArguments < 1)
3939     {
3940       return TCL_ERROR;
3941     }
3942     BackgroundChanger aBackgroundChanger;
3943     if (!aBackgroundChanger.ProcessCommandLine (theDrawInterpretor,
3944                                                 theNumberOfCommandLineArguments,
3945                                                 theCommandLineArguments))
3946     {
3947       theDrawInterpretor << "Wrong command arguments.\n"
3948                             "Type 'help "
3949                          << theCommandLineArguments[0] << "' for information about command options and its arguments.\n";
3950       return TCL_ERROR;
3951     }
3952     return TCL_OK;
3953   }
3954
3955 } // namespace
3956
3957 //==============================================================================
3958 //function : VScale
3959 //purpose  : View Scaling
3960 //==============================================================================
3961
3962 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3963 {
3964   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3965   if ( V3dView.IsNull() ) return 1;
3966
3967   if ( argc != 4 ) {
3968     di << argv[0] << "Invalid number of arguments\n";
3969     return 1;
3970   }
3971   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
3972   return 0;
3973 }
3974 //==============================================================================
3975 //function : VZBuffTrihedron
3976 //purpose  :
3977 //==============================================================================
3978
3979 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
3980                             Standard_Integer  theArgNb,
3981                             const char**      theArgVec)
3982 {
3983   Handle(V3d_View) aView = ViewerTest::CurrentView();
3984   if (aView.IsNull())
3985   {
3986     Message::SendFail ("Error: no active viewer");
3987     return 1;
3988   }
3989
3990   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
3991
3992   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
3993   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
3994   Quantity_Color                aLabelsColorX = Quantity_NOC_WHITE;
3995   Quantity_Color                aLabelsColorY = Quantity_NOC_WHITE;
3996   Quantity_Color                aLabelsColorZ = Quantity_NOC_WHITE;
3997   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
3998   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
3999   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
4000   Standard_Real                 aScale        = 0.1;
4001   Standard_Real                 aSizeRatio    = 0.8;
4002   Standard_Real                 anArrowDiam   = 0.05;
4003   Standard_Integer              aNbFacets     = 12;
4004   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4005   {
4006     Standard_CString        anArg = theArgVec[anArgIter];
4007     TCollection_AsciiString aFlag (anArg);
4008     aFlag.LowerCase();
4009     if (anUpdateTool.parseRedrawMode (aFlag))
4010     {
4011       continue;
4012     }
4013     else if (aFlag == "-on")
4014     {
4015       continue;
4016     }
4017     else if (aFlag == "-off")
4018     {
4019       aView->TriedronErase();
4020       return 0;
4021     }
4022     else if (aFlag == "-pos"
4023           || aFlag == "-position"
4024           || aFlag == "-corner")
4025     {
4026       if (++anArgIter >= theArgNb)
4027       {
4028         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4029         return 1;
4030       }
4031
4032       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
4033       aPosName.LowerCase();
4034       if (aPosName == "center")
4035       {
4036         aPosition = Aspect_TOTP_CENTER;
4037       }
4038       else if (aPosName == "left_lower"
4039             || aPosName == "lower_left"
4040             || aPosName == "leftlower"
4041             || aPosName == "lowerleft")
4042       {
4043         aPosition = Aspect_TOTP_LEFT_LOWER;
4044       }
4045       else if (aPosName == "left_upper"
4046             || aPosName == "upper_left"
4047             || aPosName == "leftupper"
4048             || aPosName == "upperleft")
4049       {
4050         aPosition = Aspect_TOTP_LEFT_UPPER;
4051       }
4052       else if (aPosName == "right_lower"
4053             || aPosName == "lower_right"
4054             || aPosName == "rightlower"
4055             || aPosName == "lowerright")
4056       {
4057         aPosition = Aspect_TOTP_RIGHT_LOWER;
4058       }
4059       else if (aPosName == "right_upper"
4060             || aPosName == "upper_right"
4061             || aPosName == "rightupper"
4062             || aPosName == "upperright")
4063       {
4064         aPosition = Aspect_TOTP_RIGHT_UPPER;
4065       }
4066       else
4067       {
4068         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'";
4069         return 1;
4070       }
4071     }
4072     else if (aFlag == "-type")
4073     {
4074       if (++anArgIter >= theArgNb)
4075       {
4076         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4077         return 1;
4078       }
4079
4080       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
4081       aTypeName.LowerCase();
4082       if (aTypeName == "wireframe"
4083        || aTypeName == "wire")
4084       {
4085         aVisType = V3d_WIREFRAME;
4086       }
4087       else if (aTypeName == "zbuffer"
4088             || aTypeName == "shaded")
4089       {
4090         aVisType = V3d_ZBUFFER;
4091       }
4092       else
4093       {
4094         Message::SendFail() << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'";
4095       }
4096     }
4097     else if (aFlag == "-scale")
4098     {
4099       if (++anArgIter >= theArgNb)
4100       {
4101         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4102         return 1;
4103       }
4104
4105       aScale = Draw::Atof (theArgVec[anArgIter]);
4106     }
4107     else if (aFlag == "-size"
4108           || aFlag == "-sizeratio")
4109     {
4110       if (++anArgIter >= theArgNb)
4111       {
4112         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4113         return 1;
4114       }
4115
4116       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
4117     }
4118     else if (aFlag == "-arrowdiam"
4119           || aFlag == "-arrowdiameter")
4120     {
4121       if (++anArgIter >= theArgNb)
4122       {
4123         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4124         return 1;
4125       }
4126
4127       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
4128     }
4129     else if (aFlag == "-nbfacets")
4130     {
4131       if (++anArgIter >= theArgNb)
4132       {
4133         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4134         return 1;
4135       }
4136
4137       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
4138     }
4139     else if (aFlag == "-colorlabel"
4140           || aFlag == "-colorlabels"
4141           || aFlag == "-colorlabelx"
4142           || aFlag == "-colorlabely"
4143           || aFlag == "-colorlabelz"
4144           || aFlag == "-colorarrowx"
4145           || aFlag == "-colorarrowy"
4146           || aFlag == "-colorarrowz")
4147     {
4148       Quantity_Color aColor;
4149       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - anArgIter - 1,
4150                                                      theArgVec + anArgIter + 1,
4151                                                      aColor);
4152       if (aNbParsed == 0)
4153       {
4154         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4155         return 1;
4156       }
4157
4158       if (aFlag == "-colorarrowx")
4159       {
4160         anArrowColorX = aColor;
4161       }
4162       else if (aFlag == "-colorarrowy")
4163       {
4164         anArrowColorY = aColor;
4165       }
4166       else if (aFlag == "-colorarrowz")
4167       {
4168         anArrowColorZ = aColor;
4169       }
4170       else if (aFlag == "-colorlabelx")
4171       {
4172         aLabelsColorX = aColor;
4173       }
4174       else if (aFlag == "-colorlabely")
4175       {
4176         aLabelsColorY = aColor;
4177       }
4178       else if (aFlag == "-colorlabelz")
4179       {
4180         aLabelsColorZ = aColor;
4181       }
4182       else
4183       {
4184         aLabelsColorZ = aLabelsColorY = aLabelsColorX = aColor;
4185       }
4186       anArgIter += aNbParsed;
4187     }
4188     else
4189     {
4190       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4191       return 1;
4192     }
4193   }
4194
4195   const Handle(V3d_Trihedron)& aTrihedron = aView->Trihedron();
4196   aTrihedron->SetArrowsColor  (anArrowColorX, anArrowColorY, anArrowColorZ);
4197   aTrihedron->SetLabelsColor  (aLabelsColorX, aLabelsColorY, aLabelsColorZ);
4198   aTrihedron->SetSizeRatio    (aSizeRatio);
4199   aTrihedron->SetNbFacets     (aNbFacets);
4200   aTrihedron->SetArrowDiameter(anArrowDiam);
4201   aTrihedron->SetScale        (aScale);
4202   aTrihedron->SetPosition     (aPosition);
4203   aTrihedron->SetWireframe    (aVisType == V3d_WIREFRAME);
4204   aTrihedron->Display (aView);
4205
4206   aView->ZFitAll();
4207   return 0;
4208 }
4209
4210 //==============================================================================
4211 //function : VRotate
4212 //purpose  : Camera Rotating
4213 //==============================================================================
4214
4215 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
4216 {
4217   Handle(V3d_View) aView = ViewerTest::CurrentView();
4218   if (aView.IsNull())
4219   {
4220     Message::SendFail ("Error: no active viewer");
4221     return 1;
4222   }
4223
4224   Standard_Boolean hasFlags = Standard_False;
4225   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4226   {
4227     Standard_CString        anArg (theArgVec[anArgIter]);
4228     TCollection_AsciiString aFlag (anArg);
4229     aFlag.LowerCase();
4230     if (aFlag == "-mousestart"
4231      || aFlag == "-mousefrom")
4232     {
4233       hasFlags = Standard_True;
4234       if (anArgIter + 2 >= theArgNb)
4235       {
4236         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4237         return 1;
4238       }
4239
4240       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4241       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4242       aView->StartRotation (anX, anY);
4243     }
4244     else if (aFlag == "-mousemove")
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->Rotation (anX, anY);
4256     }
4257     else if (theArgNb != 4
4258           && theArgNb != 7)
4259     {
4260       Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4261       return 1;
4262     }
4263   }
4264
4265   if (hasFlags)
4266   {
4267     return 0;
4268   }
4269   else if (theArgNb == 4)
4270   {
4271     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4272     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4273     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4274     aView->Rotate (anAX, anAY, anAZ);
4275     return 0;
4276   }
4277   else if (theArgNb == 7)
4278   {
4279     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4280     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4281     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4282
4283     Standard_Real anX = Draw::Atof (theArgVec[4]);
4284     Standard_Real anY = Draw::Atof (theArgVec[5]);
4285     Standard_Real anZ = Draw::Atof (theArgVec[6]);
4286
4287     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
4288     return 0;
4289   }
4290
4291   Message::SendFail ("Error: Invalid number of arguments");
4292   return 1;
4293 }
4294
4295 //==============================================================================
4296 //function : VZoom
4297 //purpose  : View zoom in / out (relative to current zoom)
4298 //==============================================================================
4299
4300 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4301   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4302   if ( V3dView.IsNull() ) {
4303     return 1;
4304   }
4305
4306   if ( argc == 2 ) {
4307     Standard_Real coef = Draw::Atof(argv[1]);
4308     if ( coef <= 0.0 ) {
4309       di << argv[1] << "Invalid value\n";
4310       return 1;
4311     }
4312     V3dView->SetZoom( Draw::Atof(argv[1]) );
4313     return 0;
4314   } else {
4315     di << argv[0] << " Invalid number of arguments\n";
4316     return 1;
4317   }
4318 }
4319
4320 //==============================================================================
4321 //function : VPan
4322 //purpose  : View panning (in pixels)
4323 //==============================================================================
4324
4325 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4326   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4327   if ( V3dView.IsNull() ) return 1;
4328
4329   if ( argc == 3 ) {
4330     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
4331     return 0;
4332   } else {
4333     di << argv[0] << " Invalid number of arguments\n";
4334     return 1;
4335   }
4336 }
4337
4338 //==============================================================================
4339 //function : VPlace
4340 //purpose  : Place the point (in pixels) at the center of the window
4341 //==============================================================================
4342 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
4343 {
4344   Handle(V3d_View) aView = ViewerTest::CurrentView();
4345   if (aView.IsNull())
4346   {
4347     Message::SendFail ("Error: no active viewer");
4348     return 1;
4349   }
4350
4351   if (theArgNb != 3)
4352   {
4353     Message::SendFail ("Syntax error: wrong number of arguments");
4354     return 1;
4355   }
4356
4357   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
4358
4359   return 0;
4360 }
4361
4362 static int VColorScale (Draw_Interpretor& theDI,
4363                         Standard_Integer  theArgNb,
4364                         const char**      theArgVec)
4365 {
4366   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
4367   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
4368   if (aContext.IsNull())
4369   {
4370     Message::SendFail ("Error: no active viewer");
4371     return 1;
4372   }
4373   if (theArgNb <= 1)
4374   {
4375     Message::SendFail() << "Error: wrong syntax at command '" << theArgVec[0] << "'";
4376     return 1;
4377   }
4378
4379   Handle(AIS_ColorScale) aColorScale;
4380   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
4381   {
4382     // find existing object
4383     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
4384     if (aColorScale.IsNull())
4385     {
4386       Message::SendFail() << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale";
4387       return 1;
4388     }
4389   }
4390
4391   if (theArgNb <= 2)
4392   {
4393     if (aColorScale.IsNull())
4394     {
4395       Message::SendFail() << "Syntax error: colorscale with a given name does not exist";
4396       return 1;
4397     }
4398
4399     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
4400           << "Min range: "            << aColorScale->GetMin() << "\n"
4401           << "Max range: "            << aColorScale->GetMax() << "\n"
4402           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
4403           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
4404           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
4405           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
4406           << "Label position: ";
4407     switch (aColorScale->GetLabelPosition())
4408     {
4409       case Aspect_TOCSP_NONE:
4410         theDI << "None\n";
4411         break;
4412       case Aspect_TOCSP_LEFT:
4413         theDI << "Left\n";
4414         break;
4415       case Aspect_TOCSP_RIGHT:
4416         theDI << "Right\n";
4417         break;
4418       case Aspect_TOCSP_CENTER:
4419         theDI << "Center\n";
4420         break;
4421     }
4422     return 0;
4423   }
4424
4425   if (aColorScale.IsNull())
4426   {
4427     aColorScale = new AIS_ColorScale();
4428     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
4429     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
4430   }
4431
4432   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
4433   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
4434   {
4435     Standard_CString        anArg = theArgVec[anArgIter];
4436     TCollection_AsciiString aFlag (anArg);
4437     aFlag.LowerCase();
4438     if (anUpdateTool.parseRedrawMode (aFlag))
4439     {
4440       continue;
4441     }
4442     else if (aFlag == "-range")
4443     {
4444       if (anArgIter + 3 >= theArgNb)
4445       {
4446         Message::SendFail() << "Error: wrong syntax at argument '" << anArg << "'";
4447         return 1;
4448       }
4449
4450       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
4451       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
4452       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
4453       if (!aRangeMin.IsRealValue (Standard_True)
4454        || !aRangeMax.IsRealValue (Standard_True))
4455       {
4456         Message::SendFail ("Syntax error: the range values should be real");
4457         return 1;
4458       }
4459       else if (!aNbIntervals.IsIntegerValue())
4460       {
4461         Message::SendFail ("Syntax error: the number of intervals should be integer");
4462         return 1;
4463       }
4464
4465       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
4466       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
4467     }
4468     else if (aFlag == "-font")
4469     {
4470       if (anArgIter + 1 >= theArgNb)
4471       {
4472         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4473         return 1;
4474       }
4475       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
4476       if (!aFontArg.IsIntegerValue())
4477       {
4478         Message::SendFail ("Syntax error: HeightFont value should be integer");
4479         return 1;
4480       }
4481
4482       aColorScale->SetTextHeight (aFontArg.IntegerValue());
4483       anArgIter += 1;
4484     }
4485     else if (aFlag == "-textpos")
4486     {
4487       if (anArgIter + 1 >= theArgNb)
4488       {
4489         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4490         return 1;
4491       }
4492
4493       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
4494       aTextPosArg.LowerCase();
4495       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
4496       if (aTextPosArg == "none")
4497       {
4498         aLabPosition = Aspect_TOCSP_NONE;
4499       }
4500       else if (aTextPosArg == "left")
4501       {
4502         aLabPosition = Aspect_TOCSP_LEFT;
4503       }
4504       else if (aTextPosArg == "right")
4505       {
4506         aLabPosition = Aspect_TOCSP_RIGHT;
4507       }
4508       else if (aTextPosArg == "center")
4509       {
4510         aLabPosition = Aspect_TOCSP_CENTER;
4511       }
4512       else
4513       {
4514         Message::SendFail() << "Syntax error: unknown position '" << aTextPosArg << "'";
4515         return 1;
4516       }
4517       aColorScale->SetLabelPosition (aLabPosition);
4518     }
4519     else if (aFlag == "-logarithmic"
4520           || aFlag == "-log")
4521     {
4522       if (anArgIter + 1 >= theArgNb)
4523       {
4524         Message::SendFail() << "Synta error at argument '" << anArg << "'";
4525         return 1;
4526       }
4527
4528       Standard_Boolean IsLog;
4529       if (!Draw::ParseOnOff(theArgVec[++anArgIter], IsLog))
4530       {
4531         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4532         return 1;
4533       }
4534       aColorScale->SetLogarithmic (IsLog);
4535     }
4536     else if (aFlag == "-huerange"
4537           || aFlag == "-hue")
4538     {
4539       if (anArgIter + 2 >= theArgNb)
4540       {
4541         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4542         return 1;
4543       }
4544
4545       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
4546       const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
4547       aColorScale->SetHueRange (aHueMin, aHueMax);
4548     }
4549     else if (aFlag == "-colorrange")
4550     {
4551       Quantity_Color aColorMin, aColorMax;
4552       Standard_Integer aNbParsed1 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4553                                                       theArgVec + (anArgIter + 1),
4554                                                       aColorMin);
4555       anArgIter += aNbParsed1;
4556       Standard_Integer aNbParsed2 = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4557                                                       theArgVec + (anArgIter + 1),
4558                                                       aColorMax);
4559       anArgIter += aNbParsed2;
4560       if (aNbParsed1 == 0
4561        || aNbParsed2 == 0)
4562       {
4563         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4564         return 1;
4565       }
4566
4567       aColorScale->SetColorRange (aColorMin, aColorMax);
4568     }
4569     else if (aFlag == "-reversed"
4570           || aFlag == "-inverted"
4571           || aFlag == "-topdown"
4572           || aFlag == "-bottomup")
4573     {
4574       Standard_Boolean toEnable = Standard_True;
4575       if (anArgIter + 1 < theArgNb
4576        && Draw::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
4577       {
4578         ++anArgIter;
4579       }
4580       aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
4581     }
4582     else if (aFlag == "-smooth"
4583           || aFlag == "-smoothtransition")
4584     {
4585       Standard_Boolean toEnable = Standard_True;
4586       if (anArgIter + 1 < theArgNb
4587        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4588       {
4589         ++anArgIter;
4590       }
4591       aColorScale->SetSmoothTransition (toEnable);
4592     }
4593     else if (aFlag == "-xy")
4594     {
4595       if (anArgIter + 2 >= theArgNb)
4596       {
4597         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4598         return 1;
4599       }
4600
4601       const TCollection_AsciiString anX (theArgVec[++anArgIter]);
4602       const TCollection_AsciiString anY (theArgVec[++anArgIter]);
4603       if (!anX.IsIntegerValue()
4604        || !anY.IsIntegerValue())
4605       {
4606         Message::SendFail ("Syntax error: coordinates should be integer values");
4607         return 1;
4608       }
4609
4610       aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
4611     }
4612     else if (aFlag == "-width"
4613           || aFlag == "-w"
4614           || aFlag == "-breadth")
4615     {
4616       if (anArgIter + 1 >= theArgNb)
4617       {
4618         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4619         return 1;
4620       }
4621
4622       const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
4623       if (!aBreadth.IsIntegerValue())
4624       {
4625         Message::SendFail ("Syntax error: a width should be an integer value");
4626         return 1;
4627       }
4628       aColorScale->SetBreadth (aBreadth.IntegerValue());
4629     }
4630     else if (aFlag == "-height"
4631           || aFlag == "-h")
4632     {
4633       if (anArgIter + 1 >= theArgNb)
4634       {
4635         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4636         return 1;
4637       }
4638
4639       const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
4640       if (!aHeight.IsIntegerValue())
4641       {
4642         Message::SendFail ("Syntax error: a width should be an integer value");
4643         return 1;
4644       }
4645       aColorScale->SetHeight (aHeight.IntegerValue());
4646     }
4647     else if (aFlag == "-color")
4648     {
4649       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4650       {
4651         Message::SendFail ("Syntax error: wrong color type. Call -colors before to set user-specified colors");
4652         return 1;
4653       }
4654       else if (anArgIter + 2 >= theArgNb)
4655       {
4656         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4657         return 1;
4658       }
4659
4660       const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
4661       if (!anInd.IsIntegerValue())
4662       {
4663         Message::SendFail ("Syntax error: Index value should be integer");
4664         return 1;
4665       }
4666       const Standard_Integer anIndex = anInd.IntegerValue();
4667       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
4668       {
4669         Message::SendFail() << "Syntax error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals();
4670         return 1;
4671       }
4672
4673       Quantity_Color aColor;
4674       Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4675                                                      theArgVec + (anArgIter + 1),
4676                                                      aColor);
4677       if (aNbParsed == 0)
4678       {
4679         Message::SendFail() << "Error: wrong syntax at '" << anArg << "'";
4680         return 1;
4681       }
4682       aColorScale->SetIntervalColor (aColor, anIndex);
4683       aColorScale->SetColorType (Aspect_TOCSD_USER);
4684       anArgIter += aNbParsed;
4685     }
4686     else if (aFlag == "-label")
4687     {
4688       if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
4689       {
4690         Message::SendFail ("Syntax error: wrong label type. Call -labels before to set user-specified labels");
4691         return 1;
4692       }
4693       else if (anArgIter + 2 >= theArgNb)
4694       {
4695         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4696         return 1;
4697       }
4698
4699       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
4700       if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
4701       {
4702         Message::SendFail() << "Syntax error: Index value should be within range 1.." << (aColorScale->GetNumberOfIntervals() + 1);
4703         return 1;
4704       }
4705
4706       TCollection_ExtendedString aText (theArgVec[anArgIter + 2], Standard_True);
4707       aColorScale->SetLabel     (aText, anIndex);
4708       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4709       anArgIter += 2;
4710     }
4711     else if (aFlag == "-labelat"
4712           || aFlag == "-labat"
4713           || aFlag == "-labelatborder"
4714           || aFlag == "-labatborder"
4715           || aFlag == "-labelatcenter"
4716           || aFlag == "-labatcenter")
4717     {
4718       Standard_Boolean toEnable = Standard_True;
4719       if (aFlag == "-labelat"
4720        || aFlag == "-labat")
4721       {
4722         Standard_Integer aLabAtBorder = -1;
4723         if (++anArgIter >= theArgNb)
4724         {
4725           TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
4726           anAtBorder.LowerCase();
4727           if (anAtBorder == "border")
4728           {
4729             aLabAtBorder = 1;
4730           }
4731           else if (anAtBorder == "center")
4732           {
4733             aLabAtBorder = 0;
4734           }
4735         }
4736         if (aLabAtBorder == -1)
4737         {
4738           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4739           return 1;
4740         }
4741         toEnable = (aLabAtBorder == 1);
4742       }
4743       else if (anArgIter + 1 < theArgNb
4744             && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
4745       {
4746         ++anArgIter;
4747       }
4748       aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
4749                                   || aFlag == "-labatcenter"
4750                                    ? !toEnable
4751                                    :  toEnable);
4752     }
4753     else if (aFlag == "-colors")
4754     {
4755       Aspect_SequenceOfColor aSeq;
4756       for (;;)
4757       {
4758         Quantity_Color aColor;
4759         Standard_Integer aNbParsed = Draw::ParseColor (theArgNb  - (anArgIter + 1),
4760                                                        theArgVec + (anArgIter + 1),
4761                                                        aColor);
4762         if (aNbParsed == 0)
4763         {
4764           break;
4765         }
4766         anArgIter += aNbParsed;
4767         aSeq.Append (aColor);
4768       }
4769       if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
4770       {
4771         Message::SendFail() << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
4772                             << aColorScale->GetNumberOfIntervals() << " intervals";
4773         return 1;
4774       }
4775
4776       aColorScale->SetColors    (aSeq);
4777       aColorScale->SetColorType (Aspect_TOCSD_USER);
4778     }
4779     else if (aFlag == "-uniform")
4780     {
4781       const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
4782       const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
4783       const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
4784       aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
4785       aColorScale->SetColorType (Aspect_TOCSD_USER);
4786     }
4787     else if (aFlag == "-labels"
4788           || aFlag == "-freelabels")
4789     {
4790       if (anArgIter + 1 >= theArgNb)
4791       {
4792         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4793         return 1;
4794       }
4795
4796       Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
4797                                  ? aColorScale->GetNumberOfIntervals() + 1
4798                                  : aColorScale->GetNumberOfIntervals();
4799       if (aFlag == "-freelabels")
4800       {
4801         ++anArgIter;
4802         aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
4803       }
4804       if (anArgIter + aNbLabels >= theArgNb)
4805       {
4806         Message::SendFail() << "Syntax error: not enough arguments. " << aNbLabels << " text labels are expected";
4807         return 1;
4808       }
4809
4810       TColStd_SequenceOfExtendedString aSeq;
4811       for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
4812       {
4813         aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter], Standard_True));
4814       }
4815       aColorScale->SetLabels (aSeq);
4816       aColorScale->SetLabelType (Aspect_TOCSD_USER);
4817     }
4818     else if (aFlag == "-title")
4819     {
4820       if (anArgIter + 1 >= theArgNb)
4821       {
4822         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4823         return 1;
4824       }
4825
4826       Standard_Boolean isTwoArgs = Standard_False;
4827       if (anArgIter + 2 < theArgNb)
4828       {
4829         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
4830         aSecondArg.LowerCase();
4831       Standard_DISABLE_DEPRECATION_WARNINGS
4832         if (aSecondArg == "none")
4833         {
4834           aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
4835           isTwoArgs = Standard_True;
4836         }
4837         else if (aSecondArg == "left")
4838         {
4839           aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
4840           isTwoArgs = Standard_True;
4841         }
4842         else if (aSecondArg == "right")
4843         {
4844           aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
4845           isTwoArgs = Standard_True;
4846         }
4847         else if (aSecondArg == "center")
4848         {
4849           aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
4850           isTwoArgs = Standard_True;
4851         }
4852       Standard_ENABLE_DEPRECATION_WARNINGS
4853       }
4854
4855       TCollection_ExtendedString aTitle(theArgVec[anArgIter + 1], Standard_True);
4856       aColorScale->SetTitle (aTitle);
4857       if (isTwoArgs)
4858       {
4859         anArgIter += 1;
4860       }
4861       anArgIter += 1;
4862     }
4863     else if (aFlag == "-demoversion"
4864           || aFlag == "-demo")
4865     {
4866       aColorScale->SetPosition (0, 0);
4867       aColorScale->SetTextHeight (16);
4868       aColorScale->SetRange (0.0, 100.0);
4869       aColorScale->SetNumberOfIntervals (10);
4870       aColorScale->SetBreadth (0);
4871       aColorScale->SetHeight  (0);
4872       aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
4873       aColorScale->SetColorType (Aspect_TOCSD_AUTO);
4874       aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
4875     }
4876     else if (aFlag == "-findcolor")
4877     {
4878       if (anArgIter + 1 >= theArgNb)
4879       {
4880         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
4881         return 1;
4882       }
4883
4884       TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
4885
4886       if (!anArg1.IsRealValue (Standard_True))
4887       {
4888         Message::SendFail ("Syntax error: the value should be real");
4889         return 1;
4890       }
4891
4892       Quantity_Color aColor;
4893       aColorScale->FindColor (anArg1.RealValue(), aColor);
4894       theDI << Quantity_Color::StringName (aColor.Name());
4895       return 0;
4896     }
4897     else
4898     {
4899       Message::SendFail() << "Syntax error at " << anArg << " - unknown argument";
4900       return 1;
4901     }
4902   }
4903
4904   Standard_Integer aWinWidth = 0, aWinHeight = 0;
4905   aView->Window()->Size (aWinWidth, aWinHeight);
4906   if (aColorScale->GetBreadth() == 0)
4907   {
4908     aColorScale->SetBreadth (aWinWidth);
4909   }
4910   if (aColorScale->GetHeight() == 0)
4911   {
4912     aColorScale->SetHeight (aWinHeight);
4913   }
4914   aColorScale->SetToUpdate();
4915   ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
4916   return 0;
4917 }
4918
4919 //==============================================================================
4920 //function : VGraduatedTrihedron
4921 //purpose  : Displays or hides a graduated trihedron
4922 //==============================================================================
4923 static Standard_Boolean GetColor (const TCollection_AsciiString& theValue,
4924                                   Quantity_Color& theColor)
4925 {
4926   Quantity_NameOfColor aColorName;
4927   TCollection_AsciiString aVal = theValue;
4928   aVal.UpperCase();
4929   if (!Quantity_Color::ColorFromName (aVal.ToCString(), aColorName))
4930   {
4931     return Standard_False;
4932   }
4933   theColor = Quantity_Color (aColorName);
4934   return Standard_True;
4935 }
4936
4937 static int VGraduatedTrihedron (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNum, const char** theArgs)
4938 {
4939   if (theArgNum < 2)
4940   {
4941     Message::SendFail() << "Syntax error: wrong number of parameters. Type 'help"
4942                         << theArgs[0] <<"' for more information";
4943     return 1;
4944   }
4945
4946   NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfArgs;
4947   TCollection_AsciiString aParseKey;
4948   for (Standard_Integer anArgIt = 1; anArgIt < theArgNum; ++anArgIt)
4949   {
4950     TCollection_AsciiString anArg (theArgs [anArgIt]);
4951
4952     if (anArg.Value (1) == '-' && !anArg.IsRealValue (Standard_True))
4953     {
4954       aParseKey = anArg;
4955       aParseKey.Remove (1);
4956       aParseKey.LowerCase();
4957       aMapOfArgs.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
4958       continue;
4959     }
4960
4961     if (aParseKey.IsEmpty())
4962     {
4963       continue;
4964     }
4965
4966     aMapOfArgs(aParseKey)->Append (anArg);
4967   }
4968
4969   // Check parameters
4970   for (NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfArgs);
4971        aMapIt.More(); aMapIt.Next())
4972   {
4973     const TCollection_AsciiString& aKey = aMapIt.Key();
4974     const Handle(TColStd_HSequenceOfAsciiString)& anArgs = aMapIt.Value();
4975
4976     // Bool key, without arguments
4977     if ((aKey.IsEqual ("on") || aKey.IsEqual ("off"))
4978         && anArgs->IsEmpty())
4979     {
4980       continue;
4981     }
4982
4983     // One argument
4984     if ( (aKey.IsEqual ("xname") || aKey.IsEqual ("yname") || aKey.IsEqual ("zname"))
4985           && anArgs->Length() == 1)
4986     {
4987       continue;
4988     }
4989
4990     // On/off arguments
4991     if ((aKey.IsEqual ("xdrawname") || aKey.IsEqual ("ydrawname") || aKey.IsEqual ("zdrawname")
4992         || aKey.IsEqual ("xdrawticks") || aKey.IsEqual ("ydrawticks") || aKey.IsEqual ("zdrawticks")
4993         || aKey.IsEqual ("xdrawvalues") || aKey.IsEqual ("ydrawvalues") || aKey.IsEqual ("zdrawvalues")
4994         || aKey.IsEqual ("drawgrid") || aKey.IsEqual ("drawaxes"))
4995         && anArgs->Length() == 1 && (anArgs->Value(1).IsEqual ("on") || anArgs->Value(1).IsEqual ("off")))
4996     {
4997       continue;
4998     }
4999
5000     // One string argument
5001     if ( (aKey.IsEqual ("xnamecolor") || aKey.IsEqual ("ynamecolor") || aKey.IsEqual ("znamecolor")
5002           || aKey.IsEqual ("xcolor") || aKey.IsEqual ("ycolor") || aKey.IsEqual ("zcolor"))
5003           && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
5004     {
5005       continue;
5006     }
5007
5008     // One integer argument
5009     if ( (aKey.IsEqual ("xticks") || aKey.IsEqual ("yticks") || aKey.IsEqual ("zticks")
5010           || aKey.IsEqual ("xticklength") || aKey.IsEqual ("yticklength") || aKey.IsEqual ("zticklength")
5011           || aKey.IsEqual ("xnameoffset") || aKey.IsEqual ("ynameoffset") || aKey.IsEqual ("znameoffset")
5012           || aKey.IsEqual ("xvaluesoffset") || aKey.IsEqual ("yvaluesoffset") || aKey.IsEqual ("zvaluesoffset"))
5013          && anArgs->Length() == 1 && anArgs->Value(1).IsIntegerValue())
5014     {
5015       continue;
5016     }
5017
5018     // One real argument
5019     if ( aKey.IsEqual ("arrowlength")
5020          && anArgs->Length() == 1 && (anArgs->Value(1).IsIntegerValue() || anArgs->Value(1).IsRealValue (Standard_True)))
5021     {
5022       continue;
5023     }
5024
5025     // Two string arguments
5026     if ( (aKey.IsEqual ("namefont") || aKey.IsEqual ("valuesfont"))
5027          && anArgs->Length() == 1 && !anArgs->Value(1).IsIntegerValue() && !anArgs->Value(1).IsRealValue (Standard_True))
5028     {
5029       continue;
5030     }
5031
5032     TCollection_AsciiString aLowerKey;
5033     aLowerKey  = "-";
5034     aLowerKey += aKey;
5035     aLowerKey.LowerCase();
5036     Message::SendFail() << "Syntax error: " << aLowerKey << " is unknown option, or the arguments are unacceptable.\n"
5037                         << "Type help for more information";
5038     return 1;
5039   }
5040
5041   Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
5042   if (anAISContext.IsNull())
5043   {
5044     Message::SendFail ("Error: no active viewer");
5045     return 1;
5046   }
5047
5048   Standard_Boolean toDisplay = Standard_True;
5049   Quantity_Color aColor;
5050   Graphic3d_GraduatedTrihedron aTrihedronData;
5051   // Process parameters
5052   Handle(TColStd_HSequenceOfAsciiString) aValues;
5053   if (aMapOfArgs.Find ("off", aValues))
5054   {
5055     toDisplay = Standard_False;
5056   }
5057
5058   // AXES NAMES
5059   if (aMapOfArgs.Find ("xname", aValues))
5060   {
5061     aTrihedronData.ChangeXAxisAspect().SetName (aValues->Value(1));
5062   }
5063   if (aMapOfArgs.Find ("yname", aValues))
5064   {
5065     aTrihedronData.ChangeYAxisAspect().SetName (aValues->Value(1));
5066   }
5067   if (aMapOfArgs.Find ("zname", aValues))
5068   {
5069     aTrihedronData.ChangeZAxisAspect().SetName (aValues->Value(1));
5070   }
5071   if (aMapOfArgs.Find ("xdrawname", aValues))
5072   {
5073     aTrihedronData.ChangeXAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5074   }
5075   if (aMapOfArgs.Find ("ydrawname", aValues))
5076   {
5077     aTrihedronData.ChangeYAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5078   }
5079   if (aMapOfArgs.Find ("zdrawname", aValues))
5080   {
5081     aTrihedronData.ChangeZAxisAspect().SetDrawName (aValues->Value(1).IsEqual ("on"));
5082   }
5083   if (aMapOfArgs.Find ("xnameoffset", aValues))
5084   {
5085     aTrihedronData.ChangeXAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5086   }
5087   if (aMapOfArgs.Find ("ynameoffset", aValues))
5088   {
5089     aTrihedronData.ChangeYAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5090   }
5091   if (aMapOfArgs.Find ("znameoffset", aValues))
5092   {
5093     aTrihedronData.ChangeZAxisAspect().SetNameOffset (aValues->Value(1).IntegerValue());
5094   }
5095
5096   // COLORS
5097   if (aMapOfArgs.Find ("xnamecolor", aValues))
5098   {
5099     if (!GetColor (aValues->Value(1), aColor))
5100     {
5101       Message::SendFail ("Syntax error: -xnamecolor wrong color name");
5102       return 1;
5103     }
5104     aTrihedronData.ChangeXAxisAspect().SetNameColor (aColor);
5105   }
5106   if (aMapOfArgs.Find ("ynamecolor", aValues))
5107   {
5108     if (!GetColor (aValues->Value(1), aColor))
5109     {
5110       Message::SendFail ("Syntax error: -ynamecolor wrong color name");
5111       return 1;
5112     }
5113     aTrihedronData.ChangeYAxisAspect().SetNameColor (aColor);
5114   }
5115   if (aMapOfArgs.Find ("znamecolor", aValues))
5116   {
5117     if (!GetColor (aValues->Value(1), aColor))
5118     {
5119       Message::SendFail ("Syntax error: -znamecolor wrong color name");
5120       return 1;
5121     }
5122     aTrihedronData.ChangeZAxisAspect().SetNameColor (aColor);
5123   }
5124   if (aMapOfArgs.Find ("xcolor", aValues))
5125   {
5126     if (!GetColor (aValues->Value(1), aColor))
5127     {
5128       Message::SendFail ("Syntax error: -xcolor wrong color name");
5129       return 1;
5130     }
5131     aTrihedronData.ChangeXAxisAspect().SetColor (aColor);
5132   }
5133   if (aMapOfArgs.Find ("ycolor", aValues))
5134   {
5135     if (!GetColor (aValues->Value(1), aColor))
5136     {
5137       Message::SendFail ("Syntax error: -ycolor wrong color name");
5138       return 1;
5139     }
5140     aTrihedronData.ChangeYAxisAspect().SetColor (aColor);
5141   }
5142   if (aMapOfArgs.Find ("zcolor", aValues))
5143   {
5144     if (!GetColor (aValues->Value(1), aColor))
5145     {
5146       Message::SendFail ("Syntax error: -zcolor wrong color name");
5147       return 1;
5148     }
5149     aTrihedronData.ChangeZAxisAspect().SetColor (aColor);
5150   }
5151
5152   // TICKMARKS
5153   if (aMapOfArgs.Find ("xticks", aValues))
5154   {
5155     aTrihedronData.ChangeXAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5156   }
5157   if (aMapOfArgs.Find ("yticks", aValues))
5158   {
5159     aTrihedronData.ChangeYAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5160   }
5161   if (aMapOfArgs.Find ("zticks", aValues))
5162   {
5163     aTrihedronData.ChangeZAxisAspect().SetTickmarksNumber (aValues->Value(1).IntegerValue());
5164   }
5165   if (aMapOfArgs.Find ("xticklength", aValues))
5166   {
5167     aTrihedronData.ChangeXAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5168   }
5169   if (aMapOfArgs.Find ("yticklength", aValues))
5170   {
5171     aTrihedronData.ChangeYAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5172   }
5173   if (aMapOfArgs.Find ("zticklength", aValues))
5174   {
5175     aTrihedronData.ChangeZAxisAspect().SetTickmarksLength (aValues->Value(1).IntegerValue());
5176   }
5177   if (aMapOfArgs.Find ("xdrawticks", aValues))
5178   {
5179     aTrihedronData.ChangeXAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5180   }
5181   if (aMapOfArgs.Find ("ydrawticks", aValues))
5182   {
5183     aTrihedronData.ChangeYAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5184   }
5185   if (aMapOfArgs.Find ("zdrawticks", aValues))
5186   {
5187     aTrihedronData.ChangeZAxisAspect().SetDrawTickmarks (aValues->Value(1).IsEqual ("on"));
5188   }
5189
5190   // VALUES
5191   if (aMapOfArgs.Find ("xdrawvalues", aValues))
5192   {
5193     aTrihedronData.ChangeXAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5194   }
5195   if (aMapOfArgs.Find ("ydrawvalues", aValues))
5196   {
5197     aTrihedronData.ChangeYAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5198   }
5199   if (aMapOfArgs.Find ("zdrawvalues", aValues))
5200   {
5201     aTrihedronData.ChangeZAxisAspect().SetDrawValues (aValues->Value(1).IsEqual ("on"));
5202   }
5203   if (aMapOfArgs.Find ("xvaluesoffset", aValues))
5204   {
5205     aTrihedronData.ChangeXAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5206   }
5207   if (aMapOfArgs.Find ("yvaluesoffset", aValues))
5208   {
5209     aTrihedronData.ChangeYAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5210   }
5211   if (aMapOfArgs.Find ("zvaluesoffset", aValues))
5212   {
5213     aTrihedronData.ChangeZAxisAspect().SetValuesOffset (aValues->Value(1).IntegerValue());
5214   }
5215
5216   // ARROWS
5217   if (aMapOfArgs.Find ("arrowlength", aValues))
5218   {
5219     aTrihedronData.SetArrowsLength ((Standard_ShortReal) aValues->Value(1).RealValue());
5220   }
5221
5222   // FONTS
5223   if (aMapOfArgs.Find ("namefont", aValues))
5224   {
5225     aTrihedronData.SetNamesFont (aValues->Value(1));
5226   }
5227   if (aMapOfArgs.Find ("valuesfont", aValues))
5228   {
5229     aTrihedronData.SetValuesFont (aValues->Value(1));
5230   }
5231
5232   if (aMapOfArgs.Find ("drawgrid", aValues))
5233   {
5234     aTrihedronData.SetDrawGrid (aValues->Value(1).IsEqual ("on"));
5235   }
5236   if (aMapOfArgs.Find ("drawaxes", aValues))
5237   {
5238     aTrihedronData.SetDrawAxes (aValues->Value(1).IsEqual ("on"));
5239   }
5240
5241   // The final step: display of erase trihedron
5242   if (toDisplay)
5243   {
5244     ViewerTest::CurrentView()->GraduatedTrihedronDisplay (aTrihedronData);
5245   }
5246   else
5247   {
5248     ViewerTest::CurrentView()->GraduatedTrihedronErase();
5249   }
5250
5251   ViewerTest::GetAISContext()->UpdateCurrentViewer();
5252   ViewerTest::CurrentView()->Redraw();
5253
5254   return 0;
5255 }
5256
5257 //==============================================================================
5258 //function : VTile
5259 //purpose  :
5260 //==============================================================================
5261 static int VTile (Draw_Interpretor& theDI,
5262                   Standard_Integer  theArgNb,
5263                   const char**      theArgVec)
5264 {
5265   Handle(V3d_View) aView = ViewerTest::CurrentView();
5266   if (aView.IsNull())
5267   {
5268     Message::SendFail ("Error: no active viewer");
5269     return 1;
5270   }
5271
5272   Graphic3d_CameraTile aTile = aView->Camera()->Tile();
5273   if (theArgNb < 2)
5274   {
5275     theDI << "Total size: " << aTile.TotalSize.x() << " " << aTile.TotalSize.y() << "\n"
5276           << "Tile  size: " << aTile.TileSize.x()  << " " << aTile.TileSize.y()  << "\n"
5277           << "Lower left: " << aTile.Offset.x()    << " " << aTile.Offset.y()    << "\n";
5278     return 0;
5279   }
5280
5281   aView->Window()->Size (aTile.TileSize.x(), aTile.TileSize.y());
5282   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5283   {
5284     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5285     anArg.LowerCase();
5286     if (anArg == "-lowerleft"
5287      || anArg == "-upperleft")
5288     {
5289       if (anArgIter + 3 < theArgNb)
5290       {
5291         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5292         return 1;
5293       }
5294       aTile.IsTopDown = (anArg == "-upperleft") == Standard_True;
5295       aTile.Offset.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5296       aTile.Offset.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5297     }
5298     else if (anArg == "-total"
5299           || anArg == "-totalsize"
5300           || anArg == "-viewsize")
5301     {
5302       if (anArgIter + 3 < theArgNb)
5303       {
5304         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5305         return 1;
5306       }
5307       aTile.TotalSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5308       aTile.TotalSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5309       if (aTile.TotalSize.x() < 1
5310        || aTile.TotalSize.y() < 1)
5311       {
5312         Message::SendFail ("Error: total size is incorrect");
5313         return 1;
5314       }
5315     }
5316     else if (anArg == "-tilesize")
5317     {
5318       if (anArgIter + 3 < theArgNb)
5319       {
5320         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
5321         return 1;
5322       }
5323
5324       aTile.TileSize.x() = Draw::Atoi (theArgVec[anArgIter + 1]);
5325       aTile.TileSize.y() = Draw::Atoi (theArgVec[anArgIter + 2]);
5326       if (aTile.TileSize.x() < 1
5327        || aTile.TileSize.y() < 1)
5328       {
5329         Message::SendFail ("Error: tile size is incorrect");
5330         return 1;
5331       }
5332     }
5333     else if (anArg == "-unset")
5334     {
5335       aView->Camera()->SetTile (Graphic3d_CameraTile());
5336       aView->Redraw();
5337       return 0;
5338     }
5339   }
5340
5341   if (aTile.TileSize.x() < 1
5342    || aTile.TileSize.y() < 1)
5343   {
5344     Message::SendFail ("Error: tile size is undefined");
5345     return 1;
5346   }
5347   else if (aTile.TotalSize.x() < 1
5348         || aTile.TotalSize.y() < 1)
5349   {
5350     Message::SendFail ("Error: total size is undefined");
5351     return 1;
5352   }
5353
5354   aView->Camera()->SetTile (aTile);
5355   aView->Redraw();
5356   return 0;
5357 }
5358
5359 //! Format ZLayer ID.
5360 inline const char* formZLayerId (const Standard_Integer theLayerId)
5361 {
5362   switch (theLayerId)
5363   {
5364     case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
5365     case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
5366     case Graphic3d_ZLayerId_Top:     return "[TOP]";
5367     case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
5368     case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
5369     case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
5370   }
5371   return "";
5372 }
5373
5374 //! Print the ZLayer information.
5375 inline void printZLayerInfo (Draw_Interpretor& theDI,
5376                              const Graphic3d_ZLayerSettings& theLayer)
5377 {
5378   if (!theLayer.Name().IsEmpty())
5379   {
5380     theDI << "  Name: " << theLayer.Name() << "\n";
5381   }
5382   if (theLayer.IsImmediate())
5383   {
5384     theDI << "  Immediate: TRUE\n";
5385   }
5386   theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
5387   theDI << "  Culling distance: "      << theLayer.CullingDistance() << "\n";
5388   theDI << "  Culling size: "          << theLayer.CullingSize() << "\n";
5389   theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
5390   theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
5391   theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
5392   if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
5393   {
5394     theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
5395   }
5396 }
5397
5398 //==============================================================================
5399 //function : VZLayer
5400 //purpose  : Test z layer operations for v3d viewer
5401 //==============================================================================
5402 static int VZLayer (Draw_Interpretor& theDI,
5403                     Standard_Integer  theArgNb,
5404                     const char**      theArgVec)
5405 {
5406   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
5407   if (aContextAIS.IsNull())
5408   {
5409     Message::SendFail ("Error: no active viewer");
5410     return 1;
5411   }
5412
5413   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
5414   if (theArgNb < 2)
5415   {
5416     TColStd_SequenceOfInteger aLayers;
5417     aViewer->GetAllZLayers (aLayers);
5418     for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5419     {
5420       theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
5421       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
5422       printZLayerInfo (theDI, aSettings);
5423     }
5424     return 1;
5425   }
5426
5427   Standard_Integer anArgIter = 1;
5428   Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5429   ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
5430   if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5431   {
5432     ++anArgIter;
5433   }
5434
5435   {
5436     TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
5437     if (aFirstArg.IsIntegerValue())
5438     {
5439       ++anArgIter;
5440       aLayerId = aFirstArg.IntegerValue();
5441     }
5442     else
5443     {
5444       if (ViewerTest::ParseZLayerName (aFirstArg.ToCString(), aLayerId))
5445       {
5446         ++anArgIter;
5447       }
5448     }
5449   }
5450
5451   Graphic3d_ZLayerId anOtherLayerId = Graphic3d_ZLayerId_UNKNOWN;
5452   for (; anArgIter < theArgNb; ++anArgIter)
5453   {
5454     // perform operation
5455     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5456     anArg.LowerCase();
5457     if (anUpdateTool.parseRedrawMode (anArg))
5458     {
5459       //
5460     }
5461     else if (anArg == "-add"
5462           || anArg == "add")
5463     {
5464       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5465       if (!aViewer->AddZLayer (aLayerId))
5466       {
5467         Message::SendFail ("Error: can not add a new z layer");
5468         return 0;
5469       }
5470
5471       theDI << aLayerId;
5472     }
5473     else if (anArg == "-insertbefore"
5474           && anArgIter + 1 < theArgNb
5475           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5476     {
5477       ++anArgIter;
5478       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5479       if (!aViewer->InsertLayerBefore (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5480       {
5481         Message::SendFail ("Error: can not add a new z layer");
5482         return 0;
5483       }
5484
5485       theDI << aLayerId;
5486     }
5487     else if (anArg == "-insertafter"
5488           && anArgIter + 1 < theArgNb
5489           && ViewerTest::ParseZLayer (theArgVec[anArgIter + 1], anOtherLayerId))
5490     {
5491       ++anArgIter;
5492       aLayerId = Graphic3d_ZLayerId_UNKNOWN;
5493       if (!aViewer->InsertLayerAfter (aLayerId, Graphic3d_ZLayerSettings(), anOtherLayerId))
5494       {
5495         Message::SendFail ("Error: can not add a new z layer");
5496         return 0;
5497       }
5498
5499       theDI << aLayerId;
5500     }
5501     else if (anArg == "-del"
5502           || anArg == "-delete"
5503           || anArg == "del")
5504     {
5505       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5506       {
5507         if (++anArgIter >= theArgNb)
5508         {
5509           Message::SendFail ("Syntax error: id of z layer to remove is missing");
5510           return 1;
5511         }
5512
5513         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5514       }
5515
5516       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
5517        || aLayerId == Graphic3d_ZLayerId_Default
5518        || aLayerId == Graphic3d_ZLayerId_Top
5519        || aLayerId == Graphic3d_ZLayerId_Topmost
5520        || aLayerId == Graphic3d_ZLayerId_TopOSD
5521        || aLayerId == Graphic3d_ZLayerId_BotOSD)
5522       {
5523         Message::SendFail ("Syntax error: standard Z layer can not be removed");
5524         return 1;
5525       }
5526
5527       // move all object displayed in removing layer to default layer
5528       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
5529            anObjIter.More(); anObjIter.Next())
5530       {
5531         const Handle(AIS_InteractiveObject)& aPrs = anObjIter.Key1();
5532         if (aPrs.IsNull()
5533          || aPrs->ZLayer() != aLayerId)
5534         {
5535           continue;
5536         }
5537         aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
5538       }
5539
5540       if (!aViewer->RemoveZLayer (aLayerId))
5541       {
5542         Message::SendFail ("Z layer can not be removed");
5543       }
5544       else
5545       {
5546         theDI << aLayerId << " ";
5547       }
5548     }
5549     else if (anArg == "-get"
5550           || anArg == "get")
5551     {
5552       TColStd_SequenceOfInteger aLayers;
5553       aViewer->GetAllZLayers (aLayers);
5554       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
5555       {
5556         theDI << aLayeriter.Value() << " ";
5557       }
5558
5559       theDI << "\n";
5560     }
5561     else if (anArg == "-name")
5562     {
5563       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5564       {
5565         Message::SendFail ("Syntax error: id of Z layer is missing");
5566         return 1;
5567       }
5568
5569       if (++anArgIter >= theArgNb)
5570       {
5571         Message::SendFail ("Syntax error: name is missing");
5572         return 1;
5573       }
5574
5575       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5576       aSettings.SetName (theArgVec[anArgIter]);
5577       aViewer->SetZLayerSettings (aLayerId, aSettings);
5578     }
5579     else if (anArg == "-origin")
5580     {
5581       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5582       {
5583         Message::SendFail ("Syntax error: id of Z layer is missing");
5584         return 1;
5585       }
5586
5587       if (anArgIter + 2 >= theArgNb)
5588       {
5589         Message::SendFail ("Syntax error: origin coordinates are missing");
5590         return 1;
5591       }
5592
5593       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5594       gp_XYZ anOrigin;
5595       anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
5596       anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
5597       anOrigin.SetZ (0.0);
5598       if (anArgIter + 3 < theArgNb)
5599       {
5600         anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
5601         anArgIter += 3;
5602       }
5603       else
5604       {
5605         anArgIter += 2;
5606       }
5607       aSettings.SetOrigin (anOrigin);
5608       aViewer->SetZLayerSettings (aLayerId, aSettings);
5609     }
5610     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5611           && anArgIter + 1 < theArgNb
5612           && (anArg == "-cullingdistance"
5613            || anArg == "-cullingdist"
5614            || anArg == "-culldistance"
5615            || anArg == "-culldist"
5616            || anArg == "-distcull"
5617            || anArg == "-distculling"
5618            || anArg == "-distanceculling"))
5619     {
5620       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5621       const Standard_Real aDist = Draw::Atof (theArgVec[++anArgIter]);
5622       aSettings.SetCullingDistance (aDist);
5623       aViewer->SetZLayerSettings (aLayerId, aSettings);
5624     }
5625     else if (aLayerId != Graphic3d_ZLayerId_UNKNOWN
5626           && anArgIter + 1 < theArgNb
5627           && (anArg == "-cullingsize"
5628            || anArg == "-cullsize"
5629            || anArg == "-sizecull"
5630            || anArg == "-sizeculling"))
5631     {
5632       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5633       const Standard_Real aSize = Draw::Atof (theArgVec[++anArgIter]);
5634       aSettings.SetCullingSize (aSize);
5635       aViewer->SetZLayerSettings (aLayerId, aSettings);
5636     }
5637     else if (anArg == "-settings"
5638           || anArg == "settings")
5639     {
5640       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5641       {
5642         if (++anArgIter >= theArgNb)
5643         {
5644           Message::SendFail ("Syntax error: id of Z layer is missing");
5645           return 1;
5646         }
5647
5648         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5649       }
5650
5651       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5652       printZLayerInfo (theDI, aSettings);
5653     }
5654     else if (anArg == "-enable"
5655           || anArg == "enable"
5656           || anArg == "-disable"
5657           || anArg == "disable")
5658     {
5659       const Standard_Boolean toEnable = anArg == "-enable"
5660                                      || anArg == "enable";
5661       if (++anArgIter >= theArgNb)
5662       {
5663         Message::SendFail ("Syntax error: option name is missing");
5664         return 1;
5665       }
5666
5667       TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
5668       aSubOp.LowerCase();
5669       if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
5670       {
5671         if (++anArgIter >= theArgNb)
5672         {
5673           Message::SendFail ("Syntax error: id of Z layer is missing");
5674           return 1;
5675         }
5676
5677         aLayerId = Draw::Atoi (theArgVec[anArgIter]);
5678       }
5679
5680       Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
5681       if (aSubOp == "depthtest"
5682        || aSubOp == "test")
5683       {
5684         aSettings.SetEnableDepthTest (toEnable);
5685       }
5686       else if (aSubOp == "depthwrite"
5687             || aSubOp == "write")
5688       {
5689         aSettings.SetEnableDepthWrite (toEnable);
5690       }
5691       else if (aSubOp == "depthclear"
5692             || aSubOp == "clear")
5693       {
5694         aSettings.SetClearDepth (toEnable);
5695       }
5696       else if (aSubOp == "depthoffset"
5697             || aSubOp == "offset")
5698       {
5699         Graphic3d_PolygonOffset aParams;
5700         aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
5701         if (toEnable)
5702         {
5703           if (anArgIter + 2 >= theArgNb)
5704           {
5705             Message::SendFail ("Syntax error: factor and units values for depth offset are missing");
5706             return 1;
5707           }
5708
5709           aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5710           aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
5711         }
5712         aSettings.SetPolygonOffset (aParams);
5713       }
5714       else if (aSubOp == "positiveoffset"
5715             || aSubOp == "poffset")
5716       {
5717         if (toEnable)
5718         {
5719           aSettings.SetDepthOffsetPositive();
5720         }
5721         else
5722         {
5723           aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
5724         }
5725       }
5726       else if (aSubOp == "negativeoffset"
5727             || aSubOp == "noffset")
5728       {
5729         if (toEnable)
5730         {
5731           aSettings.SetDepthOffsetNegative();
5732         }
5733         else
5734         {
5735           aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
5736         }
5737       }
5738       else if (aSubOp == "textureenv")
5739       {
5740         aSettings.SetEnvironmentTexture (toEnable);
5741       }
5742       else if (aSubOp == "raytracing")
5743       {
5744         aSettings.SetRaytracable (toEnable);
5745       }
5746
5747       aViewer->SetZLayerSettings (aLayerId, aSettings);
5748     }
5749     else
5750     {
5751       Message::SendFail() << "Syntax error: unknown option " << theArgVec[anArgIter];
5752       return 1;
5753     }
5754   }
5755
5756   return 0;
5757 }
5758
5759 // The interactive presentation of 2d layer item
5760 // for "vlayerline" command it provides a presentation of
5761 // line with user-defined linewidth, linetype and transparency.
5762 class V3d_LineItem : public AIS_InteractiveObject
5763 {
5764 public:
5765   // CASCADE RTTI
5766   DEFINE_STANDARD_RTTI_INLINE(V3d_LineItem,AIS_InteractiveObject)
5767
5768   // constructor
5769   Standard_EXPORT V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5770                                Standard_Real X2, Standard_Real Y2,
5771                                Aspect_TypeOfLine theType = Aspect_TOL_SOLID,
5772                                Standard_Real theWidth    = 0.5,
5773                                Standard_Real theTransp   = 1.0);
5774
5775   private:
5776
5777   void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
5778                 const Handle(Prs3d_Presentation)& thePresentation,
5779                 const Standard_Integer theMode) Standard_OVERRIDE;
5780
5781   void ComputeSelection (const Handle(SelectMgr_Selection)& /*aSelection*/,
5782                          const Standard_Integer /*aMode*/) Standard_OVERRIDE
5783   {}
5784
5785 private:
5786
5787   Standard_Real       myX1, myY1, myX2, myY2;
5788   Aspect_TypeOfLine   myType;
5789   Standard_Real       myWidth;
5790 };
5791
5792 // default constructor for line item
5793 V3d_LineItem::V3d_LineItem(Standard_Real X1, Standard_Real Y1,
5794                            Standard_Real X2, Standard_Real Y2,
5795                            Aspect_TypeOfLine theType,
5796                            Standard_Real theWidth,
5797                            Standard_Real theTransp) :
5798   myX1(X1), myY1(Y1), myX2(X2), myY2(Y2),
5799   myType(theType), myWidth(theWidth)
5800 {
5801   SetTransparency (1-theTransp);
5802 }
5803
5804 // render line
5805 void V3d_LineItem::Compute (const Handle(PrsMgr_PresentationManager3d)& /*thePresentationManager*/,
5806                             const Handle(Prs3d_Presentation)& thePresentation,
5807                             const Standard_Integer /*theMode*/)
5808 {
5809   thePresentation->Clear();
5810   Quantity_Color aColor (Quantity_NOC_RED);
5811   Standard_Integer aWidth, aHeight;
5812   ViewerTest::CurrentView()->Window()->Size (aWidth, aHeight);
5813   Handle(Graphic3d_Group) aGroup = thePresentation->CurrentGroup();
5814   Handle(Graphic3d_ArrayOfPolylines) aPrim = new Graphic3d_ArrayOfPolylines(5);
5815   aPrim->AddVertex(myX1, aHeight-myY1, 0.);
5816   aPrim->AddVertex(myX2, aHeight-myY2, 0.);
5817   Handle(Prs3d_LineAspect) anAspect = new Prs3d_LineAspect (aColor, (Aspect_TypeOfLine)myType, myWidth);
5818   aGroup->SetPrimitivesAspect (anAspect->Aspect());
5819   aGroup->AddPrimitiveArray (aPrim);
5820 }
5821
5822 //=============================================================================
5823 //function : VLayerLine
5824 //purpose  : Draws line in the v3d view layer with given attributes: linetype,
5825 //         : linewidth, transparency coefficient
5826 //============================================================================
5827 static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
5828 {
5829   // get the active view
5830   Handle(V3d_View) aView = ViewerTest::CurrentView();
5831   if (aView.IsNull())
5832   {
5833     di << "Call vinit before!\n";
5834     return 1;
5835   }
5836   else if (argc < 5)
5837   {
5838     di << "Use: " << argv[0];
5839     di << " x1 y1 x2 y2 [linewidth = 0.5] [linetype = 0] [transparency = 1]\n";
5840     di << " linetype : { 0 | 1 | 2 | 3 } \n";
5841     di << "              0 - solid  \n";
5842     di << "              1 - dashed \n";
5843     di << "              2 - dot    \n";
5844     di << "              3 - dashdot\n";
5845     di << " transparency : { 0.0 - 1.0 } \n";
5846     di << "                  0.0 - transparent\n";
5847     di << "                  1.0 - visible    \n";
5848     return 1;
5849   }
5850
5851   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
5852   // get the input params
5853   Standard_Real X1 = Draw::Atof(argv[1]);
5854   Standard_Real Y1 = Draw::Atof(argv[2]);
5855   Standard_Real X2 = Draw::Atof(argv[3]);
5856   Standard_Real Y2 = Draw::Atof(argv[4]);
5857
5858   Standard_Real aWidth = 0.5;
5859   Standard_Real aTransparency = 1.0;
5860
5861   // has width
5862   if (argc > 5)
5863     aWidth = Draw::Atof(argv[5]);
5864
5865   // select appropriate line type
5866   Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
5867   if (argc > 6
5868   && !ViewerTest::ParseLineType (argv[6], aLineType))
5869   {
5870     Message::SendFail() << "Syntax error: unknown line type '" << argv[6] << "'";
5871     return 1;
5872   }
5873
5874   // has transparency
5875   if (argc > 7)
5876   {
5877     aTransparency = Draw::Atof(argv[7]);
5878     if (aTransparency < 0 || aTransparency > 1.0)
5879       aTransparency = 1.0;
5880   }
5881
5882   static Handle (V3d_LineItem) aLine;
5883   if (!aLine.IsNull())
5884   {
5885     aContext->Erase (aLine, Standard_False);
5886   }
5887   aLine = new V3d_LineItem (X1, Y1, X2, Y2,
5888                             aLineType, aWidth,
5889                             aTransparency);
5890
5891   aContext->SetTransformPersistence (aLine, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
5892   aLine->SetZLayer (Graphic3d_ZLayerId_TopOSD);
5893   aLine->SetToUpdate();
5894   aContext->Display (aLine, Standard_True);
5895
5896   return 0;
5897 }
5898
5899
5900 //==============================================================================
5901 //function : VGrid
5902 //purpose  :
5903 //==============================================================================
5904
5905 static int VGrid (Draw_Interpretor& /*theDI*/,
5906                   Standard_Integer  theArgNb,
5907                   const char**      theArgVec)
5908 {
5909   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
5910   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
5911   if (aView.IsNull() || aViewer.IsNull())
5912   {
5913     Message::SendFail ("Error: no active viewer");
5914     return 1;
5915   }
5916
5917   Aspect_GridType     aType = aViewer->GridType();
5918   Aspect_GridDrawMode aMode = aViewer->GridDrawMode();
5919   Graphic3d_Vec2d aNewOriginXY, aNewStepXY, aNewSizeXY;
5920   Standard_Real aNewRotAngle = 0.0, aNewZOffset = 0.0;
5921   bool hasOrigin = false, hasStep = false, hasRotAngle = false, hasSize = false, hasZOffset = false;
5922   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
5923   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
5924   {
5925     TCollection_AsciiString anArg (theArgVec[anArgIter]);
5926     anArg.LowerCase();
5927     if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
5928     {
5929       continue;
5930     }
5931     else if (anArgIter + 1 < theArgNb
5932           && anArg == "-type")
5933     {
5934       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5935       anArgNext.LowerCase();
5936       if (anArgNext == "r"
5937        || anArgNext == "rect"
5938        || anArgNext == "rectangular")
5939       {
5940         aType = Aspect_GT_Rectangular;
5941       }
5942       else if (anArgNext == "c"
5943             || anArgNext == "circ"
5944             || anArgNext == "circular")
5945       {
5946         aType = Aspect_GT_Circular;
5947       }
5948       else
5949       {
5950         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5951         return 1;
5952       }
5953     }
5954     else if (anArgIter + 1 < theArgNb
5955           && anArg == "-mode")
5956     {
5957       TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
5958       anArgNext.LowerCase();
5959       if (anArgNext == "l"
5960        || anArgNext == "line"
5961        || anArgNext == "lines")
5962       {
5963         aMode = Aspect_GDM_Lines;
5964       }
5965       else if (anArgNext == "p"
5966             || anArgNext == "point"
5967             || anArgNext == "points")
5968       {
5969         aMode = Aspect_GDM_Points;
5970       }
5971       else
5972       {
5973         Message::SendFail() << "Syntax error at '" << anArgNext << "'";
5974         return 1;
5975       }
5976     }
5977     else if (anArgIter + 2 < theArgNb
5978           && (anArg == "-origin"
5979            || anArg == "-orig"))
5980     {
5981       hasOrigin = true;
5982       aNewOriginXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5983                               Draw::Atof (theArgVec[anArgIter + 2]));
5984       anArgIter += 2;
5985     }
5986     else if (anArgIter + 2 < theArgNb
5987           && anArg == "-step")
5988     {
5989       hasStep = true;
5990       aNewStepXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
5991                             Draw::Atof (theArgVec[anArgIter + 2]));
5992       if (aNewStepXY.x() <= 0.0
5993        || aNewStepXY.y() <= 0.0)
5994       {
5995         Message::SendFail() << "Syntax error: wrong step '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
5996         return 1;
5997       }
5998       anArgIter += 2;
5999     }
6000     else if (anArgIter + 1 < theArgNb
6001           && (anArg == "-angle"
6002            || anArg == "-rotangle"
6003            || anArg == "-rotationangle"))
6004     {
6005       hasRotAngle = true;
6006       aNewRotAngle = Draw::Atof (theArgVec[++anArgIter]);
6007     }
6008     else if (anArgIter + 1 < theArgNb
6009           && (anArg == "-zoffset"
6010            || anArg == "-dz"))
6011     {
6012       hasZOffset = true;
6013       aNewZOffset = Draw::Atof (theArgVec[++anArgIter]);
6014     }
6015     else if (anArgIter + 1 < theArgNb
6016           && anArg == "-radius")
6017     {
6018       hasSize = true;
6019       ++anArgIter;
6020       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter]), 0.0);
6021       if (aNewStepXY.x() <= 0.0)
6022       {
6023         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter] << "'";
6024         return 1;
6025       }
6026     }
6027     else if (anArgIter + 2 < theArgNb
6028           && anArg == "-size")
6029     {
6030       hasSize = true;
6031       aNewSizeXY.SetValues (Draw::Atof (theArgVec[anArgIter + 1]),
6032                             Draw::Atof (theArgVec[anArgIter + 2]));
6033       if (aNewStepXY.x() <= 0.0
6034        || aNewStepXY.y() <= 0.0)
6035       {
6036         Message::SendFail() << "Syntax error: wrong size '" << theArgVec[anArgIter + 1] << " " << theArgVec[anArgIter + 2] << "'";
6037         return 1;
6038       }
6039       anArgIter += 2;
6040     }
6041     else if (anArg == "r"
6042           || anArg == "rect"
6043           || anArg == "rectangular")
6044     {
6045       aType = Aspect_GT_Rectangular;
6046     }
6047     else if (anArg == "c"
6048           || anArg == "circ"
6049           || anArg == "circular")
6050     {
6051       aType = Aspect_GT_Circular;
6052     }
6053     else if (anArg == "l"
6054           || anArg == "line"
6055           || anArg == "lines")
6056     {
6057       aMode = Aspect_GDM_Lines;
6058     }
6059     else if (anArg == "p"
6060           || anArg == "point"
6061           || anArg == "points")
6062     {
6063       aMode = Aspect_GDM_Points;
6064     }
6065     else if (anArgIter + 1 >= theArgNb
6066           && anArg == "off")
6067     {
6068       aViewer->DeactivateGrid();
6069       return 0;
6070     }
6071     else
6072     {
6073       Message::SendFail() << "Syntax error at '" << anArg << "'";
6074       return 1;
6075     }
6076   }
6077
6078   if (aType == Aspect_GT_Rectangular)
6079   {
6080     Graphic3d_Vec2d anOrigXY, aStepXY;
6081     Standard_Real aRotAngle = 0.0;
6082     aViewer->RectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6083     if (hasOrigin)
6084     {
6085       anOrigXY = aNewOriginXY;
6086     }
6087     if (hasStep)
6088     {
6089       aStepXY = aNewStepXY;
6090     }
6091     if (hasRotAngle)
6092     {
6093       aRotAngle = aNewRotAngle;
6094     }
6095     aViewer->SetRectangularGridValues (anOrigXY.x(), anOrigXY.y(), aStepXY.x(), aStepXY.y(), aRotAngle);
6096     if (hasSize || hasZOffset)
6097     {
6098       Graphic3d_Vec3d aSize;
6099       aViewer->RectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6100       if (hasSize)
6101       {
6102         aSize.x() = aNewSizeXY.x();
6103         aSize.y() = aNewSizeXY.y();
6104       }
6105       if (hasZOffset)
6106       {
6107         aSize.z() = aNewZOffset;
6108       }
6109       aViewer->SetRectangularGridGraphicValues (aSize.x(), aSize.y(), aSize.z());
6110     }
6111   }
6112   else if (aType == Aspect_GT_Circular)
6113   {
6114     Graphic3d_Vec2d anOrigXY;
6115     Standard_Real aRadiusStep;
6116     Standard_Integer aDivisionNumber;
6117     Standard_Real aRotAngle = 0.0;
6118     aViewer->CircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6119     if (hasOrigin)
6120     {
6121       anOrigXY = aNewOriginXY;
6122     }
6123     if (hasStep)
6124     {
6125       aRadiusStep     = aNewStepXY[0];
6126       aDivisionNumber = (int )aNewStepXY[1];
6127       if (aDivisionNumber < 1)
6128       {
6129         Message::SendFail() << "Syntax error: invalid division number '" << aNewStepXY[1] << "'";
6130         return 1;
6131       }
6132     }
6133     if (hasRotAngle)
6134     {
6135       aRotAngle = aNewRotAngle;
6136     }
6137
6138     aViewer->SetCircularGridValues (anOrigXY.x(), anOrigXY.y(), aRadiusStep, aDivisionNumber, aRotAngle);
6139     if (hasSize || hasZOffset)
6140     {
6141       Standard_Real aRadius = 0.0, aZOffset = 0.0;
6142       aViewer->CircularGridGraphicValues (aRadius, aZOffset);
6143       if (hasSize)
6144       {
6145         aRadius = aNewSizeXY.x();
6146         if (aNewSizeXY.y() != 0.0)
6147         {
6148           Message::SendFail ("Syntax error: circular size should be specified as radius");
6149           return 1;
6150         }
6151       }
6152       if (hasZOffset)
6153       {
6154         aZOffset = aNewZOffset;
6155       }
6156       aViewer->SetCircularGridGraphicValues (aRadius, aZOffset);
6157     }
6158   }
6159   aViewer->ActivateGrid (aType, aMode);
6160   return 0;
6161 }
6162
6163 //==============================================================================
6164 //function : VPriviledgedPlane
6165 //purpose  :
6166 //==============================================================================
6167
6168 static int VPriviledgedPlane (Draw_Interpretor& theDI,
6169                               Standard_Integer  theArgNb,
6170                               const char**      theArgVec)
6171 {
6172   if (theArgNb != 1 && theArgNb != 7 && theArgNb != 10)
6173   {
6174     Message::SendFail ("Error: wrong number of arguments! See usage:");
6175     theDI.PrintHelp (theArgVec[0]);
6176     return 1;
6177   }
6178
6179   // get the active viewer
6180   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
6181   if (aViewer.IsNull())
6182   {
6183     Message::SendFail ("Error: no active viewer");
6184     return 1;
6185   }
6186
6187   if (theArgNb == 1)
6188   {
6189     gp_Ax3 aPriviledgedPlane = aViewer->PrivilegedPlane();
6190     const gp_Pnt& anOrig = aPriviledgedPlane.Location();
6191     const gp_Dir& aNorm = aPriviledgedPlane.Direction();
6192     const gp_Dir& aXDir = aPriviledgedPlane.XDirection();
6193     theDI << "Origin: " << anOrig.X() << " " << anOrig.Y() << " " << anOrig.Z() << " "
6194           << "Normal: " << aNorm.X() << " " << aNorm.Y() << " " << aNorm.Z() << " "
6195           << "X-dir: "  << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
6196     return 0;
6197   }
6198
6199   Standard_Integer anArgIdx = 1;
6200   Standard_Real anOrigX = Draw::Atof (theArgVec[anArgIdx++]);
6201   Standard_Real anOrigY = Draw::Atof (theArgVec[anArgIdx++]);
6202   Standard_Real anOrigZ = Draw::Atof (theArgVec[anArgIdx++]);
6203   Standard_Real aNormX  = Draw::Atof (theArgVec[anArgIdx++]);
6204   Standard_Real aNormY  = Draw::Atof (theArgVec[anArgIdx++]);
6205   Standard_Real aNormZ  = Draw::Atof (theArgVec[anArgIdx++]);
6206
6207   gp_Ax3 aPriviledgedPlane;
6208   gp_Pnt anOrig (anOrigX, anOrigY, anOrigZ);
6209   gp_Dir aNorm (aNormX, aNormY, aNormZ);
6210   if (theArgNb > 7)
6211   {
6212     Standard_Real aXDirX = Draw::Atof (theArgVec[anArgIdx++]);
6213     Standard_Real aXDirY = Draw::Atof (theArgVec[anArgIdx++]);
6214     Standard_Real aXDirZ = Draw::Atof (theArgVec[anArgIdx++]);
6215     gp_Dir aXDir (aXDirX, aXDirY, aXDirZ);
6216     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm, aXDir);
6217   }
6218   else
6219   {
6220     aPriviledgedPlane = gp_Ax3 (anOrig, aNorm);
6221   }
6222
6223   aViewer->SetPrivilegedPlane (aPriviledgedPlane);
6224
6225   return 0;
6226 }
6227
6228 //==============================================================================
6229 //function : VConvert
6230 //purpose  :
6231 //==============================================================================
6232
6233 static int VConvert (Draw_Interpretor& theDI,
6234                      Standard_Integer  theArgNb,
6235                      const char**      theArgVec)
6236 {
6237   // get the active view
6238   Handle(V3d_View) aView = ViewerTest::CurrentView();
6239   if (aView.IsNull())
6240   {
6241     Message::SendFail ("Error: no active viewer");
6242     return 1;
6243   }
6244
6245   enum { Model, Ray, View, Window, Grid } aMode = Model;
6246
6247   // access coordinate arguments
6248   TColStd_SequenceOfReal aCoord;
6249   Standard_Integer anArgIdx = 1;
6250   for (; anArgIdx < 4 && anArgIdx < theArgNb; ++anArgIdx)
6251   {
6252     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6253     if (!anArg.IsRealValue (Standard_True))
6254     {
6255       break;
6256     }
6257     aCoord.Append (anArg.RealValue());
6258   }
6259
6260   // non-numeric argument too early
6261   if (aCoord.IsEmpty())
6262   {
6263     Message::SendFail ("Error: wrong number of arguments! See usage:");
6264     theDI.PrintHelp (theArgVec[0]);
6265     return 1;
6266   }
6267
6268   // collect all other arguments and options
6269   for (; anArgIdx < theArgNb; ++anArgIdx)
6270   {
6271     TCollection_AsciiString anArg (theArgVec[anArgIdx]);
6272     anArg.LowerCase();
6273     if      (anArg == "window") aMode = Window;
6274     else if (anArg == "view")   aMode = View;
6275     else if (anArg == "grid")   aMode = Grid;
6276     else if (anArg == "ray")    aMode = Ray;
6277     else
6278     {
6279       Message::SendFail() << "Error: wrong argument " << anArg << "! See usage:";
6280       theDI.PrintHelp (theArgVec[0]);
6281       return 1;
6282     }
6283   }
6284
6285   // complete input checks
6286   if ((aCoord.Length() == 1 && theArgNb > 3) ||
6287       (aCoord.Length() == 2 && theArgNb > 4) ||
6288       (aCoord.Length() == 3 && theArgNb > 5))
6289   {
6290     Message::SendFail ("Error: wrong number of arguments! See usage:");
6291     theDI.PrintHelp (theArgVec[0]);
6292     return 1;
6293   }
6294
6295   Standard_Real aXYZ[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
6296   Standard_Integer aXYp[2] = {0, 0};
6297
6298   // convert one-dimensional coordinate
6299   if (aCoord.Length() == 1)
6300   {
6301     switch (aMode)
6302     {
6303       case View   : theDI << "View Vv: "   << aView->Convert ((Standard_Integer)aCoord (1)); return 0;
6304       case Window : theDI << "Window Vp: " << aView->Convert (aCoord (1)); return 0;
6305       default:
6306         Message::SendFail ("Error: wrong arguments! See usage:");
6307         theDI.PrintHelp (theArgVec[0]);
6308         return 1;
6309     }
6310   }
6311
6312   // convert 2D coordinates from projection or view reference space
6313   if (aCoord.Length() == 2)
6314   {
6315     switch (aMode)
6316     {
6317       case Model :
6318         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6319         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6320         return 0;
6321
6322       case View :
6323         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1]);
6324         theDI << "View Xv,Yv: " << aXYZ[0] << " " << aXYZ[1] << "\n";
6325         return 0;
6326
6327       case Window :
6328         aView->Convert (aCoord (1), aCoord (2), aXYp[0], aXYp[1]);
6329         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6330         return 0;
6331
6332       case Grid :
6333         aView->Convert ((Standard_Integer) aCoord (1), (Standard_Integer) aCoord (2), aXYZ[0], aXYZ[1], aXYZ[2]);
6334         aView->ConvertToGrid (aXYZ[0], aXYZ[1], aXYZ[2], aXYZ[3], aXYZ[4], aXYZ[5]);
6335         theDI << "Model X,Y,Z: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6336         return 0;
6337
6338       case Ray :
6339         aView->ConvertWithProj ((Standard_Integer) aCoord (1),
6340                                 (Standard_Integer) aCoord (2),
6341                                 aXYZ[0], aXYZ[1], aXYZ[2],
6342                                 aXYZ[3], aXYZ[4], aXYZ[5]);
6343         theDI << "Model DX,DY,DZ: " << aXYZ[3] << " " << aXYZ[4] << " " << aXYZ[5] << "\n";
6344         return 0;
6345
6346       default:
6347         Message::SendFail ("Error: wrong arguments! See usage:");
6348         theDI.PrintHelp (theArgVec[0]);
6349         return 1;
6350     }
6351   }
6352
6353   // convert 3D coordinates from view reference space
6354   else if (aCoord.Length() == 3)
6355   {
6356     switch (aMode)
6357     {
6358       case Window :
6359         aView->Convert (aCoord (1), aCoord (2), aCoord (3), aXYp[0], aXYp[1]);
6360         theDI << "Window Xp,Yp: " << aXYp[0] << " " << aXYp[1] << "\n";
6361         return 0;
6362
6363       case Grid :
6364         aView->ConvertToGrid (aCoord (1), aCoord (2), aCoord (3), aXYZ[0], aXYZ[1], aXYZ[2]);
6365         theDI << "Model X,Y,Z: " << aXYZ[0] << " " << aXYZ[1] << " " << aXYZ[2] << "\n";
6366         return 0;
6367
6368       default:
6369         Message::SendFail ("Error: wrong arguments! See usage:");
6370         theDI.PrintHelp (theArgVec[0]);
6371         return 1;
6372     }
6373   }
6374
6375   return 0;
6376 }
6377
6378 //==============================================================================
6379 //function : VFps
6380 //purpose  :
6381 //==============================================================================
6382
6383 static int VFps (Draw_Interpretor& theDI,
6384                  Standard_Integer  theArgNb,
6385                  const char**      theArgVec)
6386 {
6387   // get the active view
6388   Handle(V3d_View) aView = ViewerTest::CurrentView();
6389   if (aView.IsNull())
6390   {
6391     Message::SendFail ("Error: no active viewer");
6392     return 1;
6393   }
6394
6395   Standard_Integer aFramesNb = -1;
6396   Standard_Real aDuration = -1.0;
6397   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6398   {
6399     TCollection_AsciiString anArg (theArgVec[anArgIter]);
6400     anArg.LowerCase();
6401     if (aDuration < 0.0
6402      && anArgIter + 1 < theArgNb
6403      && (anArg == "-duration"
6404       || anArg == "-dur"
6405       || anArg == "-time"))
6406     {
6407       aDuration = Draw::Atof (theArgVec[++anArgIter]);
6408     }
6409     else if (aFramesNb < 0
6410           && anArg.IsIntegerValue())
6411     {
6412       aFramesNb = anArg.IntegerValue();
6413       if (aFramesNb <= 0)
6414       {
6415         Message::SendFail() << "Syntax error at '" << anArg << "'";
6416         return 1;
6417       }
6418     }
6419     else
6420     {
6421       Message::SendFail() << "Syntax error at '" << anArg << "'";
6422       return 1;
6423     }
6424   }
6425   if (aFramesNb < 0 && aDuration < 0.0)
6426   {
6427     aFramesNb = 100;
6428   }
6429
6430   // the time is meaningless for first call
6431   // due to async OpenGl rendering
6432   aView->Redraw();
6433
6434   // redraw view in loop to estimate average values
6435   OSD_Timer aTimer;
6436   aTimer.Start();
6437   Standard_Integer aFrameIter = 1;
6438   for (;; ++aFrameIter)
6439   {
6440     aView->Redraw();
6441     if ((aFramesNb > 0
6442       && aFrameIter >= aFramesNb)
6443      || (aDuration > 0.0
6444       && aTimer.ElapsedTime() >= aDuration))
6445     {
6446       break;
6447     }
6448   }
6449   aTimer.Stop();
6450   Standard_Real aCpu;
6451   const Standard_Real aTime = aTimer.ElapsedTime();
6452   aTimer.OSD_Chronometer::Show (aCpu);
6453
6454   const Standard_Real aFpsAver = Standard_Real(aFrameIter) / aTime;
6455   const Standard_Real aCpuAver = aCpu / Standard_Real(aFrameIter);
6456
6457   // return statistics
6458   theDI << "FPS: " << aFpsAver << "\n"
6459         << "CPU: " << (1000.0 * aCpuAver) << " msec\n";
6460
6461   // compute additional statistics in ray-tracing mode
6462   const Graphic3d_RenderingParams& aParams = aView->RenderingParams();
6463   if (aParams.Method == Graphic3d_RM_RAYTRACING)
6464   {
6465     Graphic3d_Vec2i aWinSize (0, 0);
6466     aView->Window()->Size (aWinSize.x(), aWinSize.y());
6467
6468     // 1 shadow ray and 1 secondary ray pew each bounce
6469     const Standard_Real aMRays = aWinSize.x() * aWinSize.y() * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
6470     theDI << "MRays/sec (upper bound): " << aMRays << "\n";
6471   }
6472
6473   return 0;
6474 }
6475
6476 //! Auxiliary function for parsing glsl dump level argument.
6477 static Standard_Boolean parseGlslSourceFlag (Standard_CString               theArg,
6478                                              OpenGl_ShaderProgramDumpLevel& theGlslDumpLevel)
6479 {
6480   TCollection_AsciiString aTypeStr (theArg);
6481   aTypeStr.LowerCase();
6482   if (aTypeStr == "off"
6483    || aTypeStr == "0")
6484   {
6485     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6486   }
6487   else if (aTypeStr == "short")
6488   {
6489     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Short;
6490   }
6491   else if (aTypeStr == "full"
6492         || aTypeStr == "1")
6493   {
6494     theGlslDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6495   }
6496   else
6497   {
6498     return Standard_False;
6499   }
6500   return Standard_True;
6501 }
6502
6503 //==============================================================================
6504 //function : VGlDebug
6505 //purpose  :
6506 //==============================================================================
6507
6508 static int VGlDebug (Draw_Interpretor& theDI,
6509                      Standard_Integer  theArgNb,
6510                      const char**      theArgVec)
6511 {
6512   Handle(OpenGl_GraphicDriver) aDriver;
6513   Handle(V3d_View) aView = ViewerTest::CurrentView();
6514   if (!aView.IsNull())
6515   {
6516     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aView->Viewer()->Driver());
6517   }
6518   OpenGl_Caps* aDefCaps = &ViewerTest_myDefaultCaps;
6519   OpenGl_Caps* aCaps    = !aDriver.IsNull() ? &aDriver->ChangeOptions() : NULL;
6520
6521   if (theArgNb < 2)
6522   {
6523     TCollection_AsciiString aDebActive, aSyncActive;
6524     if (aCaps == NULL)
6525     {
6526       aCaps = aDefCaps;
6527     }
6528     else
6529     {
6530       Standard_Boolean isActive = OpenGl_Context::CheckExtension ((const char* )::glGetString (GL_EXTENSIONS),
6531                                                                   "GL_ARB_debug_output");
6532       aDebActive = isActive ? " (active)" : " (inactive)";
6533       if (isActive)
6534       {
6535         // GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
6536         aSyncActive = ::glIsEnabled (0x8242) == GL_TRUE ? " (active)" : " (inactive)";
6537       }
6538     }
6539
6540     TCollection_AsciiString aGlslCodeDebugStatus = TCollection_AsciiString()
6541       + "glslSourceCode: "
6542       + (aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Off
6543          ? "Off"
6544          : aCaps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short
6545           ? "Short"
6546           : "Full")
6547       + "\n";
6548     theDI << "debug:          " << (aCaps->contextDebug      ? "1" : "0") << aDebActive  << "\n"
6549           << "sync:           " << (aCaps->contextSyncDebug  ? "1" : "0") << aSyncActive << "\n"
6550           << "glslWarn:       " << (aCaps->glslWarnings      ? "1" : "0") << "\n"
6551           << aGlslCodeDebugStatus
6552           << "extraMsg:       " << (aCaps->suppressExtraMsg  ? "0" : "1") << "\n";
6553     return 0;
6554   }
6555
6556   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6557   {
6558     Standard_CString        anArg     = theArgVec[anArgIter];
6559     TCollection_AsciiString anArgCase (anArg);
6560     anArgCase.LowerCase();
6561     Standard_Boolean toEnableDebug = Standard_True;
6562     if (anArgCase == "-glsl"
6563      || anArgCase == "-glslwarn"
6564      || anArgCase == "-glslwarns"
6565      || anArgCase == "-glslwarnings")
6566     {
6567       Standard_Boolean toShowWarns = Standard_True;
6568       if (++anArgIter < theArgNb
6569       && !Draw::ParseOnOff (theArgVec[anArgIter], toShowWarns))
6570       {
6571         --anArgIter;
6572       }
6573       aDefCaps->glslWarnings = toShowWarns;
6574       if (aCaps != NULL)
6575       {
6576         aCaps->glslWarnings = toShowWarns;
6577       }
6578     }
6579     else if (anArgCase == "-extra"
6580           || anArgCase == "-extramsg"
6581           || anArgCase == "-extramessages")
6582     {
6583       Standard_Boolean toShow = Standard_True;
6584       if (++anArgIter < theArgNb
6585       && !Draw::ParseOnOff (theArgVec[anArgIter], toShow))
6586       {
6587         --anArgIter;
6588       }
6589       aDefCaps->suppressExtraMsg = !toShow;
6590       if (aCaps != NULL)
6591       {
6592         aCaps->suppressExtraMsg = !toShow;
6593       }
6594     }
6595     else if (anArgCase == "-noextra"
6596           || anArgCase == "-noextramsg"
6597           || anArgCase == "-noextramessages")
6598     {
6599       Standard_Boolean toSuppress = Standard_True;
6600       if (++anArgIter < theArgNb
6601       && !Draw::ParseOnOff (theArgVec[anArgIter], toSuppress))
6602       {
6603         --anArgIter;
6604       }
6605       aDefCaps->suppressExtraMsg = toSuppress;
6606       if (aCaps != NULL)
6607       {
6608         aCaps->suppressExtraMsg = toSuppress;
6609       }
6610     }
6611     else if (anArgCase == "-sync")
6612     {
6613       Standard_Boolean toSync = Standard_True;
6614       if (++anArgIter < theArgNb
6615       && !Draw::ParseOnOff (theArgVec[anArgIter], toSync))
6616       {
6617         --anArgIter;
6618       }
6619       aDefCaps->contextSyncDebug = toSync;
6620       if (toSync)
6621       {
6622         aDefCaps->contextDebug = Standard_True;
6623       }
6624     }
6625     else if (anArgCase == "-glslsourcecode"
6626           || anArgCase == "-glslcode")
6627     {
6628       OpenGl_ShaderProgramDumpLevel aGslsDumpLevel = OpenGl_ShaderProgramDumpLevel_Full;
6629       if (++anArgIter < theArgNb
6630       && !parseGlslSourceFlag (theArgVec[anArgIter], aGslsDumpLevel))
6631       {
6632         --anArgIter;
6633       }
6634       aDefCaps->glslDumpLevel = aGslsDumpLevel;
6635       if (aCaps != NULL)
6636       {
6637         aCaps->glslDumpLevel = aGslsDumpLevel;
6638       }
6639     }
6640     else if (anArgCase == "-debug")
6641     {
6642       if (++anArgIter < theArgNb
6643       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnableDebug))
6644       {
6645         --anArgIter;
6646       }
6647       aDefCaps->contextDebug = toEnableDebug;
6648     }
6649     else if (Draw::ParseOnOff (anArg, toEnableDebug)
6650           && (anArgIter + 1 == theArgNb))
6651     {
6652       // simple alias to turn on almost everything
6653       aDefCaps->contextDebug     = toEnableDebug;
6654       aDefCaps->contextSyncDebug = toEnableDebug;
6655       aDefCaps->glslWarnings     = toEnableDebug;
6656       if (!toEnableDebug)
6657       {
6658         aDefCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6659       }
6660       aDefCaps->suppressExtraMsg = !toEnableDebug;
6661       if (aCaps != NULL)
6662       {
6663         aCaps->contextDebug     = toEnableDebug;
6664         aCaps->contextSyncDebug = toEnableDebug;
6665         aCaps->glslWarnings     = toEnableDebug;
6666         if (!toEnableDebug)
6667         {
6668           aCaps->glslDumpLevel = OpenGl_ShaderProgramDumpLevel_Off;
6669         }
6670         aCaps->suppressExtraMsg = !toEnableDebug;
6671       }
6672     }
6673     else
6674     {
6675       Message::SendFail() << "Syntax error at '" << anArg << "'";
6676       return 1;
6677     }
6678   }
6679
6680   return 0;
6681 }
6682
6683 //==============================================================================
6684 //function : VVbo
6685 //purpose  :
6686 //==============================================================================
6687
6688 static int VVbo (Draw_Interpretor& theDI,
6689                  Standard_Integer  theArgNb,
6690                  const char**      theArgVec)
6691 {
6692   const Standard_Boolean toSet    = (theArgNb > 1);
6693   const Standard_Boolean toUseVbo = toSet ? (Draw::Atoi (theArgVec[1]) == 0) : 1;
6694   if (toSet)
6695   {
6696     ViewerTest_myDefaultCaps.vboDisable = toUseVbo;
6697   }
6698
6699   // get the context
6700   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6701   if (aContextAIS.IsNull())
6702   {
6703     if (!toSet)
6704     {
6705       Message::SendFail ("Error: no active viewer");
6706     }
6707     return 1;
6708   }
6709   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContextAIS->CurrentViewer()->Driver());
6710   if (!aDriver.IsNull())
6711   {
6712     if (!toSet)
6713     {
6714       theDI << (aDriver->Options().vboDisable ? "0" : "1") << "\n";
6715     }
6716     else
6717     {
6718       aDriver->ChangeOptions().vboDisable = toUseVbo;
6719     }
6720   }
6721
6722   return 0;
6723 }
6724
6725 //==============================================================================
6726 //function : VCaps
6727 //purpose  :
6728 //==============================================================================
6729
6730 static int VCaps (Draw_Interpretor& theDI,
6731                   Standard_Integer  theArgNb,
6732                   const char**      theArgVec)
6733 {
6734   OpenGl_Caps* aCaps = &ViewerTest_myDefaultCaps;
6735   Handle(OpenGl_GraphicDriver)   aDriver;
6736   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
6737   if (!aContext.IsNull())
6738   {
6739     aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aContext->CurrentViewer()->Driver());
6740     aCaps   = &aDriver->ChangeOptions();
6741   }
6742
6743   if (theArgNb < 2)
6744   {
6745     theDI << "sRGB:    " << (aCaps->sRGBDisable       ? "0" : "1") << "\n";
6746     theDI << "VBO:     " << (aCaps->vboDisable        ? "0" : "1") << "\n";
6747     theDI << "Sprites: " << (aCaps->pntSpritesDisable ? "0" : "1") << "\n";
6748     theDI << "SoftMode:" << (aCaps->contextNoAccel    ? "1" : "0") << "\n";
6749     theDI << "FFP:     " << (aCaps->ffpEnable         ? "1" : "0") << "\n";
6750     theDI << "PolygonMode: " << (aCaps->usePolygonMode ? "1" : "0") << "\n";
6751     theDI << "VSync:   " <<  aCaps->swapInterval                   << "\n";
6752     theDI << "Compatible:" << (aCaps->contextCompatible ? "1" : "0") << "\n";
6753     theDI << "Stereo:  " << (aCaps->contextStereo ? "1" : "0") << "\n";
6754     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
6755     theDI << "OpaqueAlpha: " << (aCaps->buffersOpaqueAlpha ? "1" : "0") << "\n";
6756     theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
6757     theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
6758     theDI << "CompressTextures: " << (aCaps->compressedTexturesDisable ? "0" : "1") << "\n";
6759     return 0;
6760   }
6761
6762   ViewerTest_AutoUpdater anUpdateTool (aContext, ViewerTest::CurrentView());
6763   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
6764   {
6765     Standard_CString        anArg     = theArgVec[anArgIter];
6766     TCollection_AsciiString anArgCase (anArg);
6767     anArgCase.LowerCase();
6768     if (anUpdateTool.parseRedrawMode (anArg))
6769     {
6770       continue;
6771     }
6772     else if (anArgCase == "-vsync"
6773           || anArgCase == "-swapinterval")
6774     {
6775       Standard_Boolean toEnable = Standard_True;
6776       if (++anArgIter < theArgNb
6777       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6778       {
6779         --anArgIter;
6780       }
6781       aCaps->swapInterval = toEnable;
6782     }
6783     else if (anArgCase == "-ffp")
6784     {
6785       Standard_Boolean toEnable = Standard_True;
6786       if (++anArgIter < theArgNb
6787       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6788       {
6789         --anArgIter;
6790       }
6791       aCaps->ffpEnable = toEnable;
6792     }
6793     else if (anArgCase == "-polygonmode")
6794     {
6795       Standard_Boolean toEnable = Standard_True;
6796       if (++anArgIter < theArgNb
6797       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6798       {
6799         --anArgIter;
6800       }
6801       aCaps->usePolygonMode = toEnable;
6802     }
6803     else if (anArgCase == "-srgb")
6804     {
6805       Standard_Boolean toEnable = Standard_True;
6806       if (++anArgIter < theArgNb
6807       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6808       {
6809         --anArgIter;
6810       }
6811       aCaps->sRGBDisable = !toEnable;
6812     }
6813     else if (anArgCase == "-compressedtextures")
6814     {
6815       Standard_Boolean toEnable = Standard_True;
6816       if (++anArgIter < theArgNb
6817       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6818       {
6819         --anArgIter;
6820       }
6821       aCaps->compressedTexturesDisable = !toEnable;
6822     }
6823     else if (anArgCase == "-vbo")
6824     {
6825       Standard_Boolean toEnable = Standard_True;
6826       if (++anArgIter < theArgNb
6827       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6828       {
6829         --anArgIter;
6830       }
6831       aCaps->vboDisable = !toEnable;
6832     }
6833     else if (anArgCase == "-sprite"
6834           || anArgCase == "-sprites")
6835     {
6836       Standard_Boolean toEnable = Standard_True;
6837       if (++anArgIter < theArgNb
6838       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6839       {
6840         --anArgIter;
6841       }
6842       aCaps->pntSpritesDisable = !toEnable;
6843     }
6844     else if (anArgCase == "-softmode")
6845     {
6846       Standard_Boolean toEnable = Standard_True;
6847       if (++anArgIter < theArgNb
6848       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6849       {
6850         --anArgIter;
6851       }
6852       aCaps->contextNoAccel = toEnable;
6853     }
6854     else if (anArgCase == "-opaquealpha"
6855           || anArgCase == "-buffersOpaqueAlpha")
6856     {
6857       Standard_Boolean toEnable = Standard_True;
6858       if (++anArgIter < theArgNb
6859       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6860       {
6861         --anArgIter;
6862       }
6863       aCaps->buffersOpaqueAlpha = toEnable;
6864     }
6865     else if (anArgCase == "-winbuffer"
6866           || anArgCase == "-windowbuffer"
6867           || anArgCase == "-usewinbuffer"
6868           || anArgCase == "-usewindowbuffer"
6869           || anArgCase == "-usesystembuffer")
6870     {
6871       Standard_Boolean toEnable = Standard_True;
6872       if (++anArgIter < theArgNb
6873       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6874       {
6875         --anArgIter;
6876       }
6877       aCaps->useSystemBuffer = toEnable;
6878     }
6879     else if (anArgCase == "-accel"
6880           || anArgCase == "-acceleration")
6881     {
6882       Standard_Boolean toEnable = Standard_True;
6883       if (++anArgIter < theArgNb
6884       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6885       {
6886         --anArgIter;
6887       }
6888       aCaps->contextNoAccel = !toEnable;
6889     }
6890     else if (anArgCase == "-compat"
6891           || anArgCase == "-compatprofile"
6892           || anArgCase == "-compatible"
6893           || anArgCase == "-compatibleprofile")
6894     {
6895       Standard_Boolean toEnable = Standard_True;
6896       if (++anArgIter < theArgNb
6897       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6898       {
6899         --anArgIter;
6900       }
6901       aCaps->contextCompatible = toEnable;
6902       if (!aCaps->contextCompatible)
6903       {
6904         aCaps->ffpEnable = Standard_False;
6905       }
6906     }
6907     else if (anArgCase == "-core"
6908           || anArgCase == "-coreprofile")
6909     {
6910       Standard_Boolean toEnable = Standard_True;
6911       if (++anArgIter < theArgNb
6912       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6913       {
6914         --anArgIter;
6915       }
6916       aCaps->contextCompatible = !toEnable;
6917       if (!aCaps->contextCompatible)
6918       {
6919         aCaps->ffpEnable = Standard_False;
6920       }
6921     }
6922     else if (anArgCase == "-stereo"
6923           || anArgCase == "-quadbuffer")
6924     {
6925       Standard_Boolean toEnable = Standard_True;
6926       if (++anArgIter < theArgNb
6927       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
6928       {
6929         --anArgIter;
6930       }
6931       aCaps->contextStereo = toEnable;
6932     }
6933     else if (anArgCase == "-noext"
6934           || anArgCase == "-noextensions"
6935           || anArgCase == "-noextension")
6936     {
6937       Standard_Boolean toDisable = Standard_True;
6938       if (++anArgIter < theArgNb
6939       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
6940       {
6941         --anArgIter;
6942       }
6943       aCaps->contextNoExtensions = toDisable;
6944     }
6945     else if (anArgCase == "-maxversion"
6946           || anArgCase == "-upperversion"
6947           || anArgCase == "-limitversion")
6948     {
6949       Standard_Integer aVer[2] = { -2, -1 };
6950       for (Standard_Integer aValIter = 0; aValIter < 2; ++aValIter)
6951       {
6952         if (anArgIter + 1 < theArgNb)
6953         {
6954           const TCollection_AsciiString aStr (theArgVec[anArgIter + 1]);
6955           if (aStr.IsIntegerValue())
6956           {
6957             aVer[aValIter] = aStr.IntegerValue();
6958             ++anArgIter;
6959           }
6960         }
6961       }
6962       if (aVer[0] < -1
6963        || aVer[1] < -1)
6964       {
6965         Message::SendFail() << "Syntax error at '" << anArgCase << "'";
6966         return 1;
6967       }
6968       aCaps->contextMajorVersionUpper = aVer[0];
6969       aCaps->contextMinorVersionUpper = aVer[1];
6970     }
6971     else
6972     {
6973       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
6974       return 1;
6975     }
6976   }
6977   if (aCaps != &ViewerTest_myDefaultCaps)
6978   {
6979     ViewerTest_myDefaultCaps = *aCaps;
6980   }
6981   return 0;
6982 }
6983
6984 //==============================================================================
6985 //function : VMemGpu
6986 //purpose  :
6987 //==============================================================================
6988
6989 static int VMemGpu (Draw_Interpretor& theDI,
6990                     Standard_Integer  theArgNb,
6991                     const char**      theArgVec)
6992 {
6993   // get the context
6994   Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
6995   if (aContextAIS.IsNull())
6996   {
6997     Message::SendFail ("Error: no active viewer");
6998     return 1;
6999   }
7000
7001   Handle(Graphic3d_GraphicDriver) aDriver = aContextAIS->CurrentViewer()->Driver();
7002   if (aDriver.IsNull())
7003   {
7004     Message::SendFail ("Error: graphic driver not available");
7005     return 1;
7006   }
7007
7008   Standard_Size aFreeBytes = 0;
7009   TCollection_AsciiString anInfo;
7010   if (!aDriver->MemoryInfo (aFreeBytes, anInfo))
7011   {
7012     Message::SendFail ("Error: information not available");
7013     return 1;
7014   }
7015
7016   if (theArgNb > 1 && *theArgVec[1] == 'f')
7017   {
7018     theDI << Standard_Real (aFreeBytes);
7019   }
7020   else
7021   {
7022     theDI << anInfo;
7023   }
7024
7025   return 0;
7026 }
7027
7028 // ==============================================================================
7029 // function : VReadPixel
7030 // purpose  :
7031 // ==============================================================================
7032 static int VReadPixel (Draw_Interpretor& theDI,
7033                        Standard_Integer  theArgNb,
7034                        const char**      theArgVec)
7035 {
7036   // get the active view
7037   Handle(V3d_View) aView = ViewerTest::CurrentView();
7038   if (aView.IsNull())
7039   {
7040     Message::SendFail ("Error: no active viewer");
7041     return 1;
7042   }
7043   else if (theArgNb < 3)
7044   {
7045     Message::SendFail() << "Syntax error: wrong number of arguments.\n"
7046                         << "Usage: " << theArgVec[0] << " xPixel yPixel [{rgb|rgba|depth|hls|rgbf|rgbaf}=rgba] [name]";
7047     return 1;
7048   }
7049
7050   Image_Format         aFormat     = Image_Format_RGBA;
7051   Graphic3d_BufferType aBufferType = Graphic3d_BT_RGBA;
7052
7053   Standard_Integer aWidth, aHeight;
7054   aView->Window()->Size (aWidth, aHeight);
7055   const Standard_Integer anX = Draw::Atoi (theArgVec[1]);
7056   const Standard_Integer anY = Draw::Atoi (theArgVec[2]);
7057   if (anX < 0 || anX >= aWidth || anY < 0 || anY > aHeight)
7058   {
7059     Message::SendFail() << "Error: pixel coordinates (" << anX << "; " << anY << ") are out of view (" << aWidth << " x " << aHeight << ")";
7060     return 1;
7061   }
7062
7063   bool toShowName = false, toShowHls = false, toShowHex = false, toShow_sRGB = false;
7064   for (Standard_Integer anIter = 3; anIter < theArgNb; ++anIter)
7065   {
7066     TCollection_AsciiString aParam (theArgVec[anIter]);
7067     aParam.LowerCase();
7068     if (aParam == "-rgb"
7069      || aParam == "rgb"
7070      || aParam == "-srgb"
7071      || aParam == "srgb")
7072     {
7073       aFormat     = Image_Format_RGB;
7074       aBufferType = Graphic3d_BT_RGB;
7075       toShow_sRGB = aParam == "-srgb" || aParam == "srgb";
7076     }
7077     else if (aParam == "-hls"
7078           || aParam == "hls")
7079     {
7080       aFormat     = Image_Format_RGB;
7081       aBufferType = Graphic3d_BT_RGB;
7082       toShowHls   = Standard_True;
7083     }
7084     else if (aParam == "-rgbf"
7085           || aParam == "rgbf")
7086     {
7087       aFormat     = Image_Format_RGBF;
7088       aBufferType = Graphic3d_BT_RGB;
7089     }
7090     else if (aParam == "-rgba"
7091           || aParam == "rgba"
7092           || aParam == "-srgba"
7093           || aParam == "srgba")
7094     {
7095       aFormat     = Image_Format_RGBA;
7096       aBufferType = Graphic3d_BT_RGBA;
7097       toShow_sRGB = aParam == "-srgba" || aParam == "srgba";
7098     }
7099     else if (aParam == "-rgbaf"
7100           || aParam == "rgbaf")
7101     {
7102       aFormat     = Image_Format_RGBAF;
7103       aBufferType = Graphic3d_BT_RGBA;
7104     }
7105     else if (aParam == "-depth"
7106           || aParam == "depth")
7107     {
7108       aFormat     = Image_Format_GrayF;
7109       aBufferType = Graphic3d_BT_Depth;
7110     }
7111     else if (aParam == "-name"
7112           || aParam == "name")
7113     {
7114       toShowName = Standard_True;
7115     }
7116     else if (aParam == "-hex"
7117           || aParam == "hex")
7118     {
7119       toShowHex = Standard_True;
7120     }
7121     else
7122     {
7123       Message::SendFail() << "Syntax error at '" << aParam << "'";
7124       return 1;
7125     }
7126   }
7127
7128   Image_PixMap anImage;
7129   if (!anImage.InitTrash (aFormat, aWidth, aHeight))
7130   {
7131     Message::SendFail ("Error: image allocation failed");
7132     return 1;
7133   }
7134   else if (!aView->ToPixMap (anImage, aWidth, aHeight, aBufferType))
7135   {
7136     Message::SendFail ("Error: image dump failed");
7137     return 1;
7138   }
7139
7140   // redirect possible warning messages that could have been added by ToPixMap
7141   // into the Tcl interpretor (via DefaultMessenger) to cout, so that they do not
7142   // contaminate result of the command
7143   Standard_CString aWarnLog = theDI.Result();
7144   if (aWarnLog != NULL && aWarnLog[0] != '\0')
7145   {
7146     std::cout << aWarnLog << std::endl;
7147   }
7148   theDI.Reset();
7149
7150   Quantity_ColorRGBA aColor = anImage.PixelColor (anX, anY, true);
7151   if (toShowName)
7152   {
7153     if (aBufferType == Graphic3d_BT_RGBA)
7154     {
7155       theDI << Quantity_Color::StringName (aColor.GetRGB().Name()) << " " << aColor.Alpha();
7156     }
7157     else
7158     {
7159       theDI << Quantity_Color::StringName (aColor.GetRGB().Name());
7160     }
7161   }
7162   else if (toShowHex)
7163   {
7164     if (aBufferType == Graphic3d_BT_RGBA)
7165     {
7166       theDI << Quantity_ColorRGBA::ColorToHex (aColor);
7167     }
7168     else
7169     {
7170       theDI << Quantity_Color::ColorToHex (aColor.GetRGB());
7171     }
7172   }
7173   else
7174   {
7175     switch (aBufferType)
7176     {
7177       default:
7178       case Graphic3d_BT_RGB:
7179       {
7180         if (toShowHls)
7181         {
7182           theDI << aColor.GetRGB().Hue() << " " << aColor.GetRGB().Light() << " " << aColor.GetRGB().Saturation();
7183         }
7184         else if (toShow_sRGB)
7185         {
7186           const Graphic3d_Vec4 aColor_sRGB = Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor);
7187           theDI << aColor_sRGB.r() << " " << aColor_sRGB.g() << " " << aColor_sRGB.b();
7188         }
7189         else
7190         {
7191           theDI << aColor.GetRGB().Red() << " " << aColor.GetRGB().Green() << " " << aColor.GetRGB().Blue();
7192         }
7193         break;
7194       }
7195       case Graphic3d_BT_RGBA:
7196       {
7197         const Graphic3d_Vec4 aVec4 = toShow_sRGB ? Quantity_ColorRGBA::Convert_LinearRGB_To_sRGB ((Graphic3d_Vec4 )aColor) : (Graphic3d_Vec4 )aColor;
7198         theDI << aVec4.r() << " " << aVec4.g() << " " << aVec4.b() << " " << aVec4.a();
7199         break;
7200       }
7201       case Graphic3d_BT_Depth:
7202       {
7203         theDI << aColor.GetRGB().Red();
7204         break;
7205       }
7206     }
7207   }
7208
7209   return 0;
7210 }
7211
7212 //! Auxiliary presentation for an image plane.
7213 class ViewerTest_ImagePrs : public AIS_InteractiveObject
7214 {
7215 public:
7216   //! Main constructor.
7217   ViewerTest_ImagePrs (const Handle(Image_PixMap)& theImage,
7218                        const Standard_Real theWidth,
7219                        const Standard_Real theHeight,
7220                        const TCollection_AsciiString& theLabel)
7221   : myLabel (theLabel), myWidth (theWidth), myHeight(theHeight)
7222   {
7223     SetDisplayMode (0);
7224     SetHilightMode (1);
7225     myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
7226     {
7227       myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
7228       const Handle(Graphic3d_AspectFillArea3d)& aFillAspect = myDrawer->ShadingAspect()->Aspect();
7229       Graphic3d_MaterialAspect aMat;
7230       aMat.SetMaterialType (Graphic3d_MATERIAL_PHYSIC);
7231       aMat.SetAmbientColor  (Quantity_NOC_BLACK);
7232       aMat.SetDiffuseColor  (Quantity_NOC_WHITE);
7233       aMat.SetSpecularColor (Quantity_NOC_BLACK);
7234       aMat.SetEmissiveColor (Quantity_NOC_BLACK);
7235       aFillAspect->SetFrontMaterial (aMat);
7236       aFillAspect->SetTextureMap (new Graphic3d_Texture2Dmanual (theImage));
7237       aFillAspect->SetTextureMapOn();
7238     }
7239     {
7240       Handle(Prs3d_TextAspect) aTextAspect = new Prs3d_TextAspect();
7241       aTextAspect->SetHorizontalJustification (Graphic3d_HTA_CENTER);
7242       aTextAspect->SetVerticalJustification   (Graphic3d_VTA_CENTER);
7243       myDrawer->SetTextAspect (aTextAspect);
7244     }
7245     {
7246       const gp_Dir aNorm (0.0, 0.0, 1.0);
7247       myTris = new Graphic3d_ArrayOfTriangles (4, 6, true, false, true);
7248       myTris->AddVertex (gp_Pnt(-myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 0.0));
7249       myTris->AddVertex (gp_Pnt( myWidth * 0.5, -myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 0.0));
7250       myTris->AddVertex (gp_Pnt(-myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (0.0, 1.0));
7251       myTris->AddVertex (gp_Pnt( myWidth * 0.5,  myHeight * 0.5, 0.0), aNorm, gp_Pnt2d (1.0, 1.0));
7252       myTris->AddEdge (1);
7253       myTris->AddEdge (2);
7254       myTris->AddEdge (3);
7255       myTris->AddEdge (3);
7256       myTris->AddEdge (2);
7257       myTris->AddEdge (4);
7258
7259       myRect = new Graphic3d_ArrayOfPolylines (4);
7260       myRect->AddVertex (myTris->Vertice (1));
7261       myRect->AddVertex (myTris->Vertice (3));
7262       myRect->AddVertex (myTris->Vertice (4));
7263       myRect->AddVertex (myTris->Vertice (2));
7264     }
7265   }
7266
7267   //! Returns TRUE for accepted display modes.
7268   virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE { return theMode == 0 || theMode == 1; }
7269
7270   //! Compute presentation.
7271   virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& , const Handle(Prs3d_Presentation)& thePrs, const Standard_Integer theMode) Standard_OVERRIDE
7272   {
7273     switch (theMode)
7274     {
7275       case 0:
7276       {
7277         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7278         aGroup->AddPrimitiveArray (myTris);
7279         aGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
7280         aGroup->AddPrimitiveArray (myRect);
7281         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7282         return;
7283       }
7284       case 1:
7285       {
7286         Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), myLabel, gp_Pnt(0.0, 0.0, 0.0));
7287         Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
7288         aGroup->AddPrimitiveArray (myRect);
7289         aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
7290         return;
7291       }
7292     }
7293   }
7294
7295   //! Compute selection.
7296   virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, const Standard_Integer theMode) Standard_OVERRIDE
7297   {
7298     if (theMode == 0)
7299     {
7300       Handle(SelectMgr_EntityOwner) anEntityOwner = new SelectMgr_EntityOwner (this, 5);
7301       Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anEntityOwner);
7302       aSensitive->InitTriangulation (myTris->Attributes(), myTris->Indices(), TopLoc_Location());
7303       theSel->Add (aSensitive);
7304     }
7305   }
7306
7307 private:
7308   Handle(Graphic3d_ArrayOfTriangles) myTris;
7309   Handle(Graphic3d_ArrayOfPolylines) myRect;
7310   TCollection_AsciiString myLabel;
7311   Standard_Real myWidth;
7312   Standard_Real myHeight;
7313 };
7314
7315 //==============================================================================
7316 //function : VDiffImage
7317 //purpose  : The draw-command compares two images.
7318 //==============================================================================
7319
7320 static int VDiffImage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
7321 {
7322   if (theArgNb < 3)
7323   {
7324     Message::SendFail ("Syntax error: not enough arguments");
7325     return 1;
7326   }
7327
7328   Standard_Integer anArgIter = 1;
7329   TCollection_AsciiString anImgPathRef (theArgVec[anArgIter++]);
7330   TCollection_AsciiString anImgPathNew (theArgVec[anArgIter++]);
7331   TCollection_AsciiString aDiffImagePath;
7332   Standard_Real    aTolColor        = -1.0;
7333   Standard_Integer toBlackWhite     = -1;
7334   Standard_Integer isBorderFilterOn = -1;
7335   Standard_Boolean isOldSyntax = Standard_False;
7336   TCollection_AsciiString aViewName, aPrsNameRef, aPrsNameNew, aPrsNameDiff;
7337   for (; anArgIter < theArgNb; ++anArgIter)
7338   {
7339     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7340     anArg.LowerCase();
7341     if (anArgIter + 1 < theArgNb
7342      && (anArg == "-toleranceofcolor"
7343       || anArg == "-tolerancecolor"
7344       || anArg == "-tolerance"
7345       || anArg == "-toler"))
7346     {
7347       aTolColor = Atof (theArgVec[++anArgIter]);
7348       if (aTolColor < 0.0 || aTolColor > 1.0)
7349       {
7350         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7351         return 1;
7352       }
7353     }
7354     else if (anArg == "-blackwhite")
7355     {
7356       Standard_Boolean toEnable = Standard_True;
7357       if (anArgIter + 1 < theArgNb
7358        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7359       {
7360         ++anArgIter;
7361       }
7362       toBlackWhite = toEnable ? 1 : 0;
7363     }
7364     else if (anArg == "-borderfilter")
7365     {
7366       Standard_Boolean toEnable = Standard_True;
7367       if (anArgIter + 1 < theArgNb
7368        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
7369       {
7370         ++anArgIter;
7371       }
7372       isBorderFilterOn = toEnable ? 1 : 0;
7373     }
7374     else if (anArg == "-exitonclose")
7375     {
7376       ViewerTest_EventManager::ToExitOnCloseView() = true;
7377       if (anArgIter + 1 < theArgNb
7378        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToExitOnCloseView()))
7379       {
7380         ++anArgIter;
7381       }
7382     }
7383     else if (anArg == "-closeonescape"
7384           || anArg == "-closeonesc")
7385     {
7386       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
7387       if (anArgIter + 1 < theArgNb
7388        && Draw::ParseOnOff (theArgVec[anArgIter + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
7389       {
7390         ++anArgIter;
7391       }
7392     }
7393     else if (anArgIter + 3 < theArgNb
7394           && anArg == "-display")
7395     {
7396       aViewName   = theArgVec[++anArgIter];
7397       aPrsNameRef = theArgVec[++anArgIter];
7398       aPrsNameNew = theArgVec[++anArgIter];
7399       if (anArgIter + 1 < theArgNb
7400       && *theArgVec[anArgIter + 1] != '-')
7401       {
7402         aPrsNameDiff = theArgVec[++anArgIter];
7403       }
7404     }
7405     else if (aTolColor < 0.0
7406           && anArg.IsRealValue (Standard_True))
7407     {
7408       isOldSyntax = Standard_True;
7409       aTolColor = anArg.RealValue();
7410       if (aTolColor < 0.0 || aTolColor > 1.0)
7411       {
7412         Message::SendFail() << "Syntax error at '" << anArg << " " << theArgVec[anArgIter] << "'";
7413         return 1;
7414       }
7415     }
7416     else if (isOldSyntax
7417           && toBlackWhite == -1
7418           && (anArg == "0" || anArg == "1"))
7419     {
7420       toBlackWhite = anArg == "1" ? 1 : 0;
7421     }
7422     else if (isOldSyntax
7423           && isBorderFilterOn == -1
7424           && (anArg == "0" || anArg == "1"))
7425     {
7426       isBorderFilterOn = anArg == "1" ? 1 : 0;
7427     }
7428     else if (aDiffImagePath.IsEmpty())
7429     {
7430       aDiffImagePath = theArgVec[anArgIter];
7431     }
7432     else
7433     {
7434       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7435       return 1;
7436     }
7437   }
7438
7439   Handle(Image_AlienPixMap) anImgRef = new Image_AlienPixMap();
7440   Handle(Image_AlienPixMap) anImgNew = new Image_AlienPixMap();
7441   if (!anImgRef->Load (anImgPathRef))
7442   {
7443     Message::SendFail() << "Error: image file '" << anImgPathRef << "' cannot be read";
7444     return 1;
7445   }
7446   if (!anImgNew->Load (anImgPathNew))
7447   {
7448     Message::SendFail() << "Error: image file '" << anImgPathNew << "' cannot be read";
7449     return 1;
7450   }
7451
7452   // compare the images
7453   Image_Diff aComparer;
7454   Standard_Integer aDiffColorsNb = -1;
7455   if (aComparer.Init (anImgRef, anImgNew, toBlackWhite == 1))
7456   {
7457     aComparer.SetColorTolerance (aTolColor >= 0.0 ? aTolColor : 0.0);
7458     aComparer.SetBorderFilterOn (isBorderFilterOn == 1);
7459     aDiffColorsNb = aComparer.Compare();
7460     theDI << aDiffColorsNb << "\n";
7461   }
7462
7463   // save image of difference
7464   Handle(Image_AlienPixMap) aDiff;
7465   if (aDiffColorsNb > 0
7466   && (!aDiffImagePath.IsEmpty() || !aPrsNameDiff.IsEmpty()))
7467   {
7468     aDiff = new Image_AlienPixMap();
7469     if (!aDiff->InitTrash (Image_Format_Gray, anImgRef->SizeX(), anImgRef->SizeY()))
7470     {
7471       Message::SendFail() << "Error: cannot allocate memory for diff image " << anImgRef->SizeX() << "x" << anImgRef->SizeY();
7472       return 1;
7473     }
7474     aComparer.SaveDiffImage (*aDiff);
7475     if (!aDiffImagePath.IsEmpty()
7476      && !aDiff->Save (aDiffImagePath))
7477     {
7478       Message::SendFail() << "Error: diff image file '" << aDiffImagePath << "' cannot be written";
7479       return 1;
7480     }
7481   }
7482
7483   if (aViewName.IsEmpty())
7484   {
7485     return 0;
7486   }
7487
7488   ViewerTest_Names aViewNames (aViewName);
7489   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
7490   {
7491     TCollection_AsciiString aCommand = TCollection_AsciiString ("vclose ") + aViewNames.GetViewName();
7492     theDI.Eval (aCommand.ToCString());
7493   }
7494
7495   Standard_Integer aPxLeft = 0;
7496   Standard_Integer aPxTop  = 0;
7497   Standard_Integer aWinSizeX = int(anImgRef->SizeX() * 2);
7498   Standard_Integer aWinSizeY = !aDiff.IsNull() && !aPrsNameDiff.IsEmpty()
7499                               ? int(anImgRef->SizeY() * 2)
7500                               : int(anImgRef->SizeY());
7501   TCollection_AsciiString aDisplayName;
7502   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aWinSizeX, aWinSizeY,
7503                                                             aViewName, aDisplayName);
7504
7505   Standard_Real aRatio = anImgRef->Ratio();
7506   Standard_Real aSizeX = 1.0;
7507   Standard_Real aSizeY = aSizeX / aRatio;
7508   {
7509     OSD_Path aPath (anImgPathRef);
7510     TCollection_AsciiString aLabelRef;
7511     if (!aPath.Name().IsEmpty())
7512     {
7513       aLabelRef = aPath.Name() + aPath.Extension();
7514     }
7515     aLabelRef += TCollection_AsciiString() + "\n" + int(anImgRef->SizeX()) + "x" + int(anImgRef->SizeY());
7516
7517     Handle(ViewerTest_ImagePrs) anImgRefPrs = new ViewerTest_ImagePrs (anImgRef, aSizeX, aSizeY, aLabelRef);
7518     gp_Trsf aTrsfRef;
7519     aTrsfRef.SetTranslationPart (gp_Vec (-aSizeX * 0.5, 0.0, 0.0));
7520     anImgRefPrs->SetLocalTransformation (aTrsfRef);
7521     ViewerTest::Display (aPrsNameRef, anImgRefPrs, false, true);
7522   }
7523   {
7524     OSD_Path aPath (anImgPathNew);
7525     TCollection_AsciiString aLabelNew;
7526     if (!aPath.Name().IsEmpty())
7527     {
7528       aLabelNew = aPath.Name() + aPath.Extension();
7529     }
7530     aLabelNew += TCollection_AsciiString() + "\n" + int(anImgNew->SizeX()) + "x" + int(anImgNew->SizeY());
7531
7532     Handle(ViewerTest_ImagePrs) anImgNewPrs = new ViewerTest_ImagePrs (anImgNew, aSizeX, aSizeY, aLabelNew);
7533     gp_Trsf aTrsfRef;
7534     aTrsfRef.SetTranslationPart (gp_Vec (aSizeX * 0.5, 0.0, 0.0));
7535     anImgNewPrs->SetLocalTransformation (aTrsfRef);
7536     ViewerTest::Display (aPrsNameNew, anImgNewPrs, false, true);
7537   }
7538   Handle(ViewerTest_ImagePrs) anImgDiffPrs;
7539   if (!aDiff.IsNull())
7540   {
7541     anImgDiffPrs = new ViewerTest_ImagePrs (aDiff, aSizeX, aSizeY, TCollection_AsciiString() + "Difference: " + aDiffColorsNb + " pixels");
7542     gp_Trsf aTrsfDiff;
7543     aTrsfDiff.SetTranslationPart (gp_Vec (0.0, -aSizeY, 0.0));
7544     anImgDiffPrs->SetLocalTransformation (aTrsfDiff);
7545   }
7546   if (!aPrsNameDiff.IsEmpty())
7547   {
7548     ViewerTest::Display (aPrsNameDiff, anImgDiffPrs, false, true);
7549   }
7550   ViewerTest::CurrentView()->SetProj (V3d_Zpos);
7551   ViewerTest::CurrentView()->FitAll();
7552   return 0;
7553 }
7554
7555 //=======================================================================
7556 //function : VSelect
7557 //purpose  : Emulates different types of selection by mouse:
7558 //           1) single click selection
7559 //           2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)
7560 //           3) selection with polygon having corners at
7561 //           pixel positions (x1,y1),...,(xn,yn)
7562 //           4) any of these selections with shift button pressed
7563 //=======================================================================
7564 static Standard_Integer VSelect (Draw_Interpretor& ,
7565                                  Standard_Integer theNbArgs,
7566                                  const char** theArgVec)
7567 {
7568   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
7569   if (aCtx.IsNull())
7570   {
7571     Message::SendFail ("Error: no active viewer");
7572     return 1;
7573   }
7574
7575   NCollection_Sequence<Graphic3d_Vec2i> aPnts;
7576   bool toAllowOverlap = false;
7577   AIS_SelectionScheme aSelScheme = AIS_SelectionScheme_Replace;
7578   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7579   {
7580     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7581     anArg.LowerCase();
7582     if (anArg == "-allowoverlap")
7583     {
7584       toAllowOverlap = true;
7585       if (anArgIter + 1 < theNbArgs
7586        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAllowOverlap))
7587       {
7588         ++anArgIter;
7589       }
7590     }
7591     else if (anArgIter + 1 < theNbArgs
7592           && anArg.IsIntegerValue()
7593           && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
7594     {
7595       const TCollection_AsciiString anArgNext (theArgVec[++anArgIter]);
7596       aPnts.Append (Graphic3d_Vec2i (anArg.IntegerValue(), anArgNext.IntegerValue()));
7597     }
7598     else if (anArgIter + 1 == theNbArgs
7599           && anArg.IsIntegerValue())
7600     {
7601       if (anArg.IntegerValue() == 1)
7602       {
7603         aSelScheme = AIS_SelectionScheme_XOR;
7604       }
7605     }
7606     else
7607     {
7608       Message::SendFail() << "Syntax error at '" << anArg << "'";
7609       return 1;
7610     }
7611   }
7612
7613   if (toAllowOverlap)
7614   {
7615     aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap);
7616   }
7617
7618   Handle(ViewerTest_EventManager) aCurrentEventManager = ViewerTest::CurrentEventManager();
7619   if (aPnts.IsEmpty())
7620   {
7621     aCtx->SelectDetected (aSelScheme);
7622     aCtx->CurrentViewer()->Invalidate();
7623   }
7624   else if (aPnts.Length() == 2)
7625   {
7626     if (toAllowOverlap
7627      && aPnts.First().y() < aPnts.Last().y())
7628     {
7629       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7630     }
7631     else if (!toAllowOverlap
7632            && aPnts.First().y() > aPnts.Last().y())
7633     {
7634       std::swap (aPnts.ChangeFirst(), aPnts.ChangeLast());
7635     }
7636     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme == AIS_SelectionScheme_XOR);
7637   }
7638   else
7639   {
7640     aCurrentEventManager->SelectInViewer (aPnts, aSelScheme == AIS_SelectionScheme_XOR);
7641   }
7642   aCurrentEventManager->FlushViewEvents (aCtx, ViewerTest::CurrentView(), true);
7643   return 0;
7644 }
7645
7646 //=======================================================================
7647 //function : VMoveTo
7648 //purpose  : Emulates cursor movement to defined pixel position
7649 //=======================================================================
7650 static Standard_Integer VMoveTo (Draw_Interpretor& theDI,
7651                                 Standard_Integer theNbArgs,
7652                                 const char**     theArgVec)
7653 {
7654   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
7655   const Handle(V3d_View)&               aView    = ViewerTest::CurrentView();
7656   if (aContext.IsNull())
7657   {
7658     Message::SendFail ("Error: no active viewer");
7659     return 1;
7660   }
7661
7662   Graphic3d_Vec2i aMousePos (IntegerLast(), IntegerLast());
7663   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
7664   {
7665     TCollection_AsciiString anArgStr (theArgVec[anArgIter]);
7666     anArgStr.LowerCase();
7667     if (anArgStr == "-reset"
7668      || anArgStr == "-clear")
7669     {
7670       if (anArgIter + 1 < theNbArgs)
7671       {
7672         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter + 1] << "'";
7673         return 1;
7674       }
7675
7676       const Standard_Boolean toEchoGrid = aContext->CurrentViewer()->IsGridActive()
7677                                        && aContext->CurrentViewer()->GridEcho();
7678       if (toEchoGrid)
7679       {
7680         aContext->CurrentViewer()->HideGridEcho (aView);
7681       }
7682       if (aContext->ClearDetected() || toEchoGrid)
7683       {
7684         aContext->CurrentViewer()->RedrawImmediate();
7685       }
7686       return 0;
7687     }
7688     else if (aMousePos.x() == IntegerLast()
7689           && anArgStr.IsIntegerValue())
7690     {
7691       aMousePos.x() = anArgStr.IntegerValue();
7692     }
7693     else if (aMousePos.y() == IntegerLast()
7694           && anArgStr.IsIntegerValue())
7695     {
7696       aMousePos.y() = anArgStr.IntegerValue();
7697     }
7698     else
7699     {
7700       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
7701       return 1;
7702     }
7703   }
7704
7705   if (aMousePos.x() == IntegerLast()
7706    || aMousePos.y() == IntegerLast())
7707   {
7708     Message::SendFail ("Syntax error: wrong number of arguments");
7709     return 1;
7710   }
7711
7712   ViewerTest::CurrentEventManager()->ResetPreviousMoveTo();
7713   ViewerTest::CurrentEventManager()->UpdateMousePosition (aMousePos, Aspect_VKeyMouse_NONE, Aspect_VKeyFlags_NONE, false);
7714   ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
7715
7716   gp_Pnt aTopPnt (RealLast(), RealLast(), RealLast());
7717   const Handle(SelectMgr_EntityOwner)& aDetOwner = aContext->DetectedOwner();
7718   for (Standard_Integer aDetIter = 1; aDetIter <= aContext->MainSelector()->NbPicked(); ++aDetIter)
7719   {
7720     if (aContext->MainSelector()->Picked (aDetIter) == aDetOwner)
7721     {
7722       aTopPnt = aContext->MainSelector()->PickedPoint (aDetIter);
7723       break;
7724     }
7725   }
7726   theDI << aTopPnt.X() << " " << aTopPnt.Y() << " " << aTopPnt.Z();
7727   return 0;
7728 }
7729
7730 namespace
7731 {
7732   //! Global map storing all animations registered in ViewerTest.
7733   static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
7734
7735   //! The animation calling the Draw Harness command.
7736   class ViewerTest_AnimationProc : public AIS_Animation
7737   {
7738   public:
7739
7740     //! Main constructor.
7741     ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
7742                               Draw_Interpretor* theDI,
7743                               const TCollection_AsciiString& theCommand)
7744     : AIS_Animation (theAnimationName),
7745       myDrawInter(theDI),
7746       myCommand  (theCommand)
7747     {
7748       //
7749     }
7750
7751   protected:
7752
7753     //! Evaluate the command.
7754     virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
7755     {
7756       TCollection_AsciiString aCmd = myCommand;
7757       replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
7758       replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
7759       replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
7760       replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
7761       replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
7762       myDrawInter->Eval (aCmd.ToCString());
7763     }
7764
7765     //! Find the keyword in the command and replace it with value.
7766     //! @return the position of the keyword to pass value
7767     void replace (TCollection_AsciiString&       theCmd,
7768                   const TCollection_AsciiString& theKey,
7769                   const TCollection_AsciiString& theVal)
7770     {
7771       TCollection_AsciiString aCmd (theCmd);
7772       aCmd.LowerCase();
7773       const Standard_Integer aPos = aCmd.Search (theKey);
7774       if (aPos == -1)
7775       {
7776         return;
7777       }
7778
7779       TCollection_AsciiString aPart1, aPart2;
7780       Standard_Integer aPart1To = aPos - 1;
7781       if (aPart1To >= 1
7782        && aPart1To <= theCmd.Length())
7783       {
7784         aPart1 = theCmd.SubString (1, aPart1To);
7785       }
7786
7787       Standard_Integer aPart2From = aPos + theKey.Length();
7788       if (aPart2From >= 1
7789        && aPart2From <= theCmd.Length())
7790       {
7791         aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
7792       }
7793
7794       theCmd = aPart1 + theVal + aPart2;
7795     }
7796
7797   protected:
7798
7799     Draw_Interpretor*       myDrawInter;
7800     TCollection_AsciiString myCommand;
7801
7802   };
7803
7804   //! Replace the animation with the new one.
7805   static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
7806                                 Handle(AIS_Animation)&       theAnimation,
7807                                 const Handle(AIS_Animation)& theAnimationNew)
7808   {
7809     theAnimationNew->CopyFrom (theAnimation);
7810     if (!theParentAnimation.IsNull())
7811     {
7812       theParentAnimation->Replace (theAnimation, theAnimationNew);
7813     }
7814     else
7815     {
7816       ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
7817       ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
7818     }
7819     theAnimation = theAnimationNew;
7820   }
7821
7822   //! Parse the point.
7823   static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
7824   {
7825     const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
7826     if (!anXYZ[0].IsRealValue (Standard_True)
7827      || !anXYZ[1].IsRealValue (Standard_True)
7828      || !anXYZ[2].IsRealValue (Standard_True))
7829     {
7830       return Standard_False;
7831     }
7832
7833     thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
7834     return Standard_True;
7835   }
7836
7837   //! Parse the quaternion.
7838   static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
7839   {
7840     const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
7841     if (!anXYZW[0].IsRealValue (Standard_True)
7842      || !anXYZW[1].IsRealValue (Standard_True)
7843      || !anXYZW[2].IsRealValue (Standard_True)
7844      || !anXYZW[3].IsRealValue (Standard_True))
7845     {
7846       return Standard_False;
7847     }
7848
7849     theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
7850     return Standard_True;
7851   }
7852
7853   //! Auxiliary class for flipping image upside-down.
7854   class ImageFlipper
7855   {
7856   public:
7857
7858     //! Empty constructor.
7859     ImageFlipper() : myTmp (NCollection_BaseAllocator::CommonBaseAllocator()) {}
7860
7861     //! Perform flipping.
7862     Standard_Boolean FlipY (Image_PixMap& theImage)
7863     {
7864       if (theImage.IsEmpty()
7865        || theImage.SizeX() == 0
7866        || theImage.SizeY() == 0)
7867       {
7868         return Standard_False;
7869       }
7870
7871       const Standard_Size aRowSize = theImage.SizeRowBytes();
7872       if (myTmp.Size() < aRowSize
7873       && !myTmp.Allocate (aRowSize))
7874       {
7875         return Standard_False;
7876       }
7877
7878       // for odd height middle row should be left as is
7879       Standard_Size aNbRowsHalf = theImage.SizeY() / 2;
7880       for (Standard_Size aRowT = 0, aRowB = theImage.SizeY() - 1; aRowT < aNbRowsHalf; ++aRowT, --aRowB)
7881       {
7882         Standard_Byte* aTop = theImage.ChangeRow (aRowT);
7883         Standard_Byte* aBot = theImage.ChangeRow (aRowB);
7884         memcpy (myTmp.ChangeData(), aTop,         aRowSize);
7885         memcpy (aTop,               aBot,         aRowSize);
7886         memcpy (aBot,               myTmp.Data(), aRowSize);
7887       }
7888       return Standard_True;
7889     }
7890
7891   private:
7892     NCollection_Buffer myTmp;
7893   };
7894
7895 }
7896
7897 //=================================================================================================
7898 //function : VViewParams
7899 //purpose  : Gets or sets AIS View characteristics
7900 //=================================================================================================
7901 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
7902 {
7903   Handle(V3d_View) aView = ViewerTest::CurrentView();
7904   if (aView.IsNull())
7905   {
7906     Message::SendFail ("Error: no active viewer");
7907     return 1;
7908   }
7909
7910   Standard_Boolean toSetProj     = Standard_False;
7911   Standard_Boolean toSetUp       = Standard_False;
7912   Standard_Boolean toSetAt       = Standard_False;
7913   Standard_Boolean toSetEye      = Standard_False;
7914   Standard_Boolean toSetScale    = Standard_False;
7915   Standard_Boolean toSetSize     = Standard_False;
7916   Standard_Boolean toSetCenter2d = Standard_False;
7917   Standard_Real    aViewScale = aView->Scale();
7918   Standard_Real    aViewSize  = 1.0;
7919   Graphic3d_Vec2i  aCenter2d;
7920   gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
7921   aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
7922   aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
7923   aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
7924   aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
7925   if (theArgsNb == 1)
7926   {
7927     // print all of the available view parameters
7928     char aText[4096];
7929     Sprintf (aText,
7930              "Scale: %g\n"
7931              "Proj:  %12g %12g %12g\n"
7932              "Up:    %12g %12g %12g\n"
7933              "At:    %12g %12g %12g\n"
7934              "Eye:   %12g %12g %12g\n",
7935               aViewScale,
7936               aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7937               aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7938               aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
7939               aViewEye.X(),  aViewEye.Y(),  aViewEye.Z());
7940     theDi << aText;
7941     return 0;
7942   }
7943
7944   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
7945   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
7946   {
7947     TCollection_AsciiString anArg (theArgVec[anArgIter]);
7948     anArg.LowerCase();
7949     if (anUpdateTool.parseRedrawMode (anArg))
7950     {
7951       continue;
7952     }
7953     else if (anArg == "-cmd"
7954           || anArg == "-command"
7955           || anArg == "-args")
7956     {
7957       char aText[4096];
7958       Sprintf (aText,
7959                "-scale %g "
7960                "-proj %g %g %g "
7961                "-up %g %g %g "
7962                "-at %g %g %g\n",
7963                 aViewScale,
7964                 aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
7965                 aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
7966                 aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
7967       theDi << aText;
7968     }
7969     else if (anArg == "-scale"
7970           || anArg == "-size")
7971     {
7972       if (anArgIter + 1 < theArgsNb
7973        && *theArgVec[anArgIter + 1] != '-')
7974       {
7975         const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
7976         if (aValueArg.IsRealValue (Standard_True))
7977         {
7978           ++anArgIter;
7979           if (anArg == "-scale")
7980           {
7981             toSetScale = Standard_True;
7982             aViewScale = aValueArg.RealValue();
7983           }
7984           else if (anArg == "-size")
7985           {
7986             toSetSize = Standard_True;
7987             aViewSize = aValueArg.RealValue();
7988           }
7989           continue;
7990         }
7991       }
7992       if (anArg == "-scale")
7993       {
7994         theDi << "Scale: " << aView->Scale() << "\n";
7995       }
7996       else if (anArg == "-size")
7997       {
7998         Graphic3d_Vec2d aSizeXY;
7999         aView->Size (aSizeXY.x(), aSizeXY.y());
8000         theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
8001       }
8002     }
8003     else if (anArg == "-eye"
8004           || anArg == "-at"
8005           || anArg == "-up"
8006           || anArg == "-proj")
8007     {
8008       if (anArgIter + 3 < theArgsNb)
8009       {
8010         gp_XYZ anXYZ;
8011         if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
8012         {
8013           anArgIter += 3;
8014           if (anArg == "-eye")
8015           {
8016             toSetEye = Standard_True;
8017             aViewEye = anXYZ;
8018           }
8019           else if (anArg == "-at")
8020           {
8021             toSetAt = Standard_True;
8022             aViewAt = anXYZ;
8023           }
8024           else if (anArg == "-up")
8025           {
8026             toSetUp = Standard_True;
8027             aViewUp = anXYZ;
8028           }
8029           else if (anArg == "-proj")
8030           {
8031             toSetProj = Standard_True;
8032             aViewProj = anXYZ;
8033           }
8034           continue;
8035         }
8036       }
8037
8038       if (anArg == "-eye")
8039       {
8040         theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
8041       }
8042       else if (anArg == "-at")
8043       {
8044         theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
8045       }
8046       else if (anArg == "-up")
8047       {
8048         theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
8049       }
8050       else if (anArg == "-proj")
8051       {
8052         theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
8053       }
8054     }
8055     else if (anArg == "-center")
8056     {
8057       if (anArgIter + 2 < theArgsNb)
8058       {
8059         const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
8060         const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
8061         if (anX.IsIntegerValue()
8062          && anY.IsIntegerValue())
8063         {
8064           toSetCenter2d = Standard_True;
8065           aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
8066         }
8067       }
8068     }
8069     else
8070     {
8071       Message::SendFail() << "Syntax error at '" << anArg << "'";
8072       return 1;
8073     }
8074   }
8075
8076   // change view parameters in proper order
8077   if (toSetScale)
8078   {
8079     aView->SetScale (aViewScale);
8080   }
8081   if (toSetSize)
8082   {
8083     aView->SetSize (aViewSize);
8084   }
8085   if (toSetEye)
8086   {
8087     aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
8088   }
8089   if (toSetAt)
8090   {
8091     aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
8092   }
8093   if (toSetProj)
8094   {
8095     aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
8096   }
8097   if (toSetUp)
8098   {
8099     aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
8100   }
8101   if (toSetCenter2d)
8102   {
8103     aView->SetCenter (aCenter2d.x(), aCenter2d.y());
8104   }
8105
8106   return 0;
8107 }
8108
8109 //==============================================================================
8110 //function : V2DMode
8111 //purpose  :
8112 //==============================================================================
8113 static Standard_Integer V2DMode (Draw_Interpretor&, Standard_Integer theArgsNb, const char** theArgVec)
8114 {
8115   bool is2dMode = true;
8116   Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView());
8117   if (aV3dView.IsNull())
8118   {
8119     Message::SendFail ("Error: no active viewer");
8120     return 1;
8121   }
8122   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
8123   {
8124     const TCollection_AsciiString anArg = theArgVec[anArgIt];
8125     TCollection_AsciiString anArgCase = anArg;
8126     anArgCase.LowerCase();
8127     if (anArgIt + 1 < theArgsNb
8128      && anArgCase == "-name")
8129     {
8130       ViewerTest_Names aViewNames (theArgVec[++anArgIt]);
8131       TCollection_AsciiString aViewName = aViewNames.GetViewName();
8132       if (!ViewerTest_myViews.IsBound1 (aViewName))
8133       {
8134         Message::SendFail() << "Syntax error: unknown view '" << theArgVec[anArgIt - 1] << "'";
8135         return 1;
8136       }
8137       aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest_myViews.Find1 (aViewName));
8138     }
8139     else if (anArgCase == "-mode")
8140     {
8141       if (anArgIt + 1 < theArgsNb
8142        && Draw::ParseOnOff (theArgVec[anArgIt + 1], is2dMode))
8143       {
8144         ++anArgIt;
8145       }
8146     }
8147     else if (Draw::ParseOnOff (theArgVec[anArgIt], is2dMode))
8148     {
8149       //
8150     }
8151     else
8152     {
8153       Message::SendFail() << "Syntax error: unknown argument " << anArg;
8154       return 1;
8155     }
8156   }
8157
8158   aV3dView->SetView2DMode (is2dMode);
8159   return 0;
8160 }
8161
8162 //==============================================================================
8163 //function : VAnimation
8164 //purpose  :
8165 //==============================================================================
8166 static Standard_Integer VAnimation (Draw_Interpretor& theDI,
8167                                     Standard_Integer  theArgNb,
8168                                     const char**      theArgVec)
8169 {
8170   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
8171   if (theArgNb < 2)
8172   {
8173     for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
8174          anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
8175     {
8176       theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
8177     }
8178     return 0;
8179   }
8180   if (aCtx.IsNull())
8181   {
8182     Message::SendFail ("Error: no active viewer");
8183     return 1;
8184   }
8185
8186   Standard_Integer anArgIter = 1;
8187   TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
8188   if (aNameArg.IsEmpty())
8189   {
8190     Message::SendFail ("Syntax error: animation name is not defined");
8191     return 1;
8192   }
8193
8194   TCollection_AsciiString aNameArgLower = aNameArg;
8195   aNameArgLower.LowerCase();
8196   if (aNameArgLower == "-reset"
8197    || aNameArgLower == "-clear")
8198   {
8199     ViewerTest_AnimationTimelineMap.Clear();
8200     return 0;
8201   }
8202   else if (aNameArg.Value (1) == '-')
8203   {
8204     Message::SendFail() << "Syntax error: invalid animation name '" << aNameArg  << "'";
8205     return 1;
8206   }
8207
8208   const char* aNameSplitter = "/";
8209   Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
8210   if (aSplitPos == -1)
8211   {
8212     aNameSplitter = ".";
8213     aSplitPos = aNameArg.Search (aNameSplitter);
8214   }
8215
8216   // find existing or create a new animation by specified name within syntax "parent.child".
8217   Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
8218   for (; !aNameArg.IsEmpty();)
8219   {
8220     TCollection_AsciiString aNameParent;
8221     if (aSplitPos != -1)
8222     {
8223       if (aSplitPos == aNameArg.Length())
8224       {
8225         Message::SendFail ("Syntax error: animation name is not defined");
8226         return 1;
8227       }
8228
8229       aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
8230       aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
8231
8232       aSplitPos = aNameArg.Search (aNameSplitter);
8233     }
8234     else
8235     {
8236       aNameParent = aNameArg;
8237       aNameArg.Clear();
8238     }
8239
8240     if (anAnimation.IsNull())
8241     {
8242       if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
8243       {
8244         anAnimation = new AIS_Animation (aNameParent);
8245         ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
8246       }
8247       aRootAnimation = anAnimation;
8248     }
8249     else
8250     {
8251       aParentAnimation = anAnimation;
8252       anAnimation = aParentAnimation->Find (aNameParent);
8253       if (anAnimation.IsNull())
8254       {
8255         anAnimation = new AIS_Animation (aNameParent);
8256         aParentAnimation->Add (anAnimation);
8257       }
8258     }
8259   }
8260
8261   if (anArgIter >= theArgNb)
8262   {
8263     // just print the list of children
8264     for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
8265     {
8266       theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
8267     }
8268     return 0;
8269   }
8270
8271   // animation parameters
8272   Standard_Boolean toPlay = Standard_False;
8273   Standard_Real aPlaySpeed     = 1.0;
8274   Standard_Real aPlayStartTime = anAnimation->StartPts();
8275   Standard_Real aPlayDuration  = anAnimation->Duration();
8276   Standard_Boolean isFreeCamera = Standard_False;
8277   Standard_Boolean isLockLoop   = Standard_False;
8278
8279   // video recording parameters
8280   TCollection_AsciiString aRecFile;
8281   Image_VideoParams aRecParams;
8282
8283   Handle(V3d_View) aView = ViewerTest::CurrentView();
8284   for (; anArgIter < theArgNb; ++anArgIter)
8285   {
8286     TCollection_AsciiString anArg (theArgVec[anArgIter]);
8287     anArg.LowerCase();
8288     // general options
8289     if (anArg == "-reset"
8290      || anArg == "-clear")
8291     {
8292       anAnimation->Clear();
8293     }
8294     else if (anArg == "-remove"
8295           || anArg == "-del"
8296           || anArg == "-delete")
8297     {
8298       if (!aParentAnimation.IsNull())
8299       {
8300         ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
8301       }
8302       else
8303       {
8304         aParentAnimation->Remove (anAnimation);
8305       }
8306     }
8307     // playback options
8308     else if (anArg == "-play")
8309     {
8310       toPlay = Standard_True;
8311       if (++anArgIter < theArgNb)
8312       {
8313         if (*theArgVec[anArgIter] == '-')
8314         {
8315           --anArgIter;
8316           continue;
8317         }
8318         aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
8319
8320         if (++anArgIter < theArgNb)
8321         {
8322           if (*theArgVec[anArgIter] == '-')
8323           {
8324             --anArgIter;
8325             continue;
8326           }
8327           aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8328         }
8329       }
8330     }
8331     else if (anArg == "-resume")
8332     {
8333       toPlay = Standard_True;
8334       aPlayStartTime = anAnimation->ElapsedTime();
8335       if (++anArgIter < theArgNb)
8336       {
8337         if (*theArgVec[anArgIter] == '-')
8338         {
8339           --anArgIter;
8340           continue;
8341         }
8342
8343         aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
8344       }
8345     }
8346     else if (anArg == "-playspeed"
8347           || anArg == "-speed")
8348     {
8349       if (++anArgIter >= theArgNb)
8350       {
8351         Message::SendFail() << "Syntax error at " << anArg << "";
8352         return 1;
8353       }
8354       aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
8355     }
8356     else if (anArg == "-lock"
8357           || anArg == "-lockloop"
8358           || anArg == "-playlockloop")
8359     {
8360       isLockLoop = Standard_True;
8361     }
8362     else if (anArg == "-freecamera"
8363           || anArg == "-playfreecamera"
8364           || anArg == "-freelook")
8365     {
8366       isFreeCamera = Standard_True;
8367     }
8368     // video recodring options
8369     else if (anArg == "-rec"
8370           || anArg == "-record")
8371     {
8372       if (++anArgIter >= theArgNb)
8373       {
8374         Message::SendFail() << "Syntax error at " << anArg;
8375         return 1;
8376       }
8377
8378       aRecFile = theArgVec[anArgIter];
8379       if (aRecParams.FpsNum <= 0)
8380       {
8381         aRecParams.FpsNum = 24;
8382       }
8383
8384       if (anArgIter + 2 < theArgNb
8385       && *theArgVec[anArgIter + 1] != '-'
8386       && *theArgVec[anArgIter + 2] != '-')
8387       {
8388         TCollection_AsciiString aWidthArg  (theArgVec[anArgIter + 1]);
8389         TCollection_AsciiString aHeightArg (theArgVec[anArgIter + 2]);
8390         if (aWidthArg .IsIntegerValue()
8391          && aHeightArg.IsIntegerValue())
8392         {
8393           aRecParams.Width  = aWidthArg .IntegerValue();
8394           aRecParams.Height = aHeightArg.IntegerValue();
8395           anArgIter += 2;
8396         }
8397       }
8398     }
8399     else if (anArg == "-fps")
8400     {
8401       if (++anArgIter >= theArgNb)
8402       {
8403         Message::SendFail() << "Syntax error at " << anArg;
8404         return 1;
8405       }
8406
8407       TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
8408       Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
8409       if (aSplitIndex == 0)
8410       {
8411         aRecParams.FpsNum = aFpsArg.IntegerValue();
8412       }
8413       else
8414       {
8415         const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
8416         aFpsArg.Split (aFpsArg.Length() - 1);
8417         const TCollection_AsciiString aNumStr = aFpsArg;
8418         aRecParams.FpsNum = aNumStr.IntegerValue();
8419         aRecParams.FpsDen = aDenStr.IntegerValue();
8420         if (aRecParams.FpsDen < 1)
8421         {
8422           Message::SendFail() << "Syntax error at " << anArg;
8423           return 1;
8424         }
8425       }
8426     }
8427     else if (anArg == "-format")
8428     {
8429       if (++anArgIter >= theArgNb)
8430       {
8431         Message::SendFail() << "Syntax error at " << anArg;
8432         return 1;
8433       }
8434       aRecParams.Format = theArgVec[anArgIter];
8435     }
8436     else if (anArg == "-pix_fmt"
8437           || anArg == "-pixfmt"
8438           || anArg == "-pixelformat")
8439     {
8440       if (++anArgIter >= theArgNb)
8441       {
8442         Message::SendFail() << "Syntax error at " << anArg;
8443         return 1;
8444       }
8445       aRecParams.PixelFormat = theArgVec[anArgIter];
8446     }
8447     else if (anArg == "-codec"
8448           || anArg == "-vcodec"
8449           || anArg == "-videocodec")
8450     {
8451       if (++anArgIter >= theArgNb)
8452       {
8453         Message::SendFail() << "Syntax error at " << anArg;
8454         return 1;
8455       }
8456       aRecParams.VideoCodec = theArgVec[anArgIter];
8457     }
8458     else if (anArg == "-crf"
8459           || anArg == "-preset"
8460           || anArg == "-qp")
8461     {
8462       const TCollection_AsciiString aParamName = anArg.SubString (2, anArg.Length());
8463       if (++anArgIter >= theArgNb)
8464       {
8465         Message::SendFail() << "Syntax error at " << anArg;
8466         return 1;
8467       }
8468
8469       aRecParams.VideoCodecParams.Bind (aParamName, theArgVec[anArgIter]);
8470     }
8471     // animation definition options
8472     else if (anArg == "-start"
8473           || anArg == "-starttime"
8474           || anArg == "-startpts")
8475     {
8476       if (++anArgIter >= theArgNb)
8477       {
8478         Message::SendFail() << "Syntax error at " << anArg;
8479         return 1;
8480       }
8481
8482       anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
8483       aRootAnimation->UpdateTotalDuration();
8484     }
8485     else if (anArg == "-end"
8486           || anArg == "-endtime"
8487           || anArg == "-endpts")
8488     {
8489       if (++anArgIter >= theArgNb)
8490       {
8491         Message::SendFail() << "Syntax error at " << anArg;
8492         return 1;
8493       }
8494
8495       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
8496       aRootAnimation->UpdateTotalDuration();
8497     }
8498     else if (anArg == "-dur"
8499           || anArg == "-duration")
8500     {
8501       if (++anArgIter >= theArgNb)
8502       {
8503         Message::SendFail() << "Syntax error at " << anArg;
8504         return 1;
8505       }
8506
8507       anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
8508       aRootAnimation->UpdateTotalDuration();
8509     }
8510     else if (anArg == "-command"
8511           || anArg == "-cmd"
8512           || anArg == "-invoke"
8513           || anArg == "-eval"
8514           || anArg == "-proc")
8515     {
8516       if (++anArgIter >= theArgNb)
8517       {
8518         Message::SendFail() << "Syntax error at " << anArg;
8519         return 1;
8520       }
8521
8522       Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
8523       replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
8524     }
8525     else if (anArg == "-objecttrsf"
8526           || anArg == "-objectransformation"
8527           || anArg == "-objtransformation"
8528           || anArg == "-objtrsf"
8529           || anArg == "-object"
8530           || anArg == "-obj")
8531     {
8532       if (++anArgIter >= theArgNb)
8533       {
8534         Message::SendFail() << "Syntax error at " << anArg;
8535         return 1;
8536       }
8537
8538       TCollection_AsciiString anObjName (theArgVec[anArgIter]);
8539       const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
8540       Handle(AIS_InteractiveObject) anObject;
8541       if (!aMapOfAIS.Find2 (anObjName, anObject))
8542       {
8543         Message::SendFail() << "Syntax error: wrong object name at " << anArg;
8544         return 1;
8545       }
8546
8547       gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
8548       gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
8549       gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
8550       Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
8551       Standard_Boolean isTrsfSet = Standard_False;
8552       Standard_Integer aTrsfArgIter = anArgIter + 1;
8553       for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
8554       {
8555         TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
8556         aTrsfArg.LowerCase();
8557         const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
8558         if (aTrsfArg.StartsWith ("-rotation")
8559          || aTrsfArg.StartsWith ("-rot"))
8560         {
8561           isTrsfSet = Standard_True;
8562           if (aTrsfArgIter + 4 >= theArgNb
8563           || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
8564           {
8565             Message::SendFail() << "Syntax error at " << aTrsfArg;
8566             return 1;
8567           }
8568           aTrsfArgIter += 4;
8569         }
8570         else if (aTrsfArg.StartsWith ("-location")
8571               || aTrsfArg.StartsWith ("-loc"))
8572         {
8573           isTrsfSet = Standard_True;
8574           if (aTrsfArgIter + 3 >= theArgNb
8575           || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
8576           {
8577             Message::SendFail() << "Syntax error at " << aTrsfArg;
8578             return 1;
8579           }
8580           aTrsfArgIter += 3;
8581         }
8582         else if (aTrsfArg.StartsWith ("-scale"))
8583         {
8584           isTrsfSet = Standard_True;
8585           if (++aTrsfArgIter >= theArgNb)
8586           {
8587             Message::SendFail() << "Syntax error at " << aTrsfArg;
8588             return 1;
8589           }
8590
8591           const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
8592           if (!aScaleStr.IsRealValue (Standard_True))
8593           {
8594             Message::SendFail() << "Syntax error at " << aTrsfArg;
8595             return 1;
8596           }
8597           aScales[anIndex] = aScaleStr.RealValue();
8598         }
8599         else
8600         {
8601           anArgIter = aTrsfArgIter - 1;
8602           break;
8603         }
8604       }
8605       if (!isTrsfSet)
8606       {
8607         Message::SendFail() << "Syntax error at " << anArg;
8608         return 1;
8609       }
8610       else if (aTrsfArgIter >= theArgNb)
8611       {
8612         anArgIter = theArgNb;
8613       }
8614
8615       aTrsfs[0].SetRotation        (aRotQuats[0]);
8616       aTrsfs[1].SetRotation        (aRotQuats[1]);
8617       aTrsfs[0].SetTranslationPart (aLocPnts[0]);
8618       aTrsfs[1].SetTranslationPart (aLocPnts[1]);
8619       aTrsfs[0].SetScaleFactor     (aScales[0]);
8620       aTrsfs[1].SetScaleFactor     (aScales[1]);
8621
8622       Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
8623       replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
8624     }
8625     else if (anArg == "-viewtrsf"
8626           || anArg == "-view")
8627     {
8628       Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
8629       if (aCamAnimation.IsNull())
8630       {
8631         aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
8632         replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
8633       }
8634
8635       Handle(Graphic3d_Camera) aCams[2] =
8636       {
8637         new Graphic3d_Camera (aCamAnimation->View()->Camera()),
8638         new Graphic3d_Camera (aCamAnimation->View()->Camera())
8639       };
8640
8641       Standard_Boolean isTrsfSet = Standard_False;
8642       Standard_Integer aViewArgIter = anArgIter + 1;
8643       for (; aViewArgIter < theArgNb; ++aViewArgIter)
8644       {
8645         TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
8646         aViewArg.LowerCase();
8647         const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
8648         if (aViewArg.StartsWith ("-scale"))
8649         {
8650           isTrsfSet = Standard_True;
8651           if (++aViewArgIter >= theArgNb)
8652           {
8653             Message::SendFail() << "Syntax error at " << anArg;
8654             return 1;
8655           }
8656
8657           const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
8658           if (!aScaleStr.IsRealValue (Standard_True))
8659           {
8660             Message::SendFail() << "Syntax error at " << aViewArg;
8661             return 1;
8662           }
8663           Standard_Real aScale = aScaleStr.RealValue();
8664           aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
8665           aCams[anIndex]->SetScale (aScale);
8666         }
8667         else if (aViewArg.StartsWith ("-eye")
8668               || aViewArg.StartsWith ("-center")
8669               || aViewArg.StartsWith ("-at")
8670               || aViewArg.StartsWith ("-up"))
8671         {
8672           isTrsfSet = Standard_True;
8673           gp_XYZ anXYZ;
8674           if (aViewArgIter + 3 >= theArgNb
8675           || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
8676           {
8677             Message::SendFail() << "Syntax error at " << aViewArg;
8678             return 1;
8679           }
8680           aViewArgIter += 3;
8681
8682           if (aViewArg.StartsWith ("-eye"))
8683           {
8684             aCams[anIndex]->SetEye (anXYZ);
8685           }
8686           else if (aViewArg.StartsWith ("-center")
8687                 || aViewArg.StartsWith ("-at"))
8688           {
8689             aCams[anIndex]->SetCenter (anXYZ);
8690           }
8691           else if (aViewArg.StartsWith ("-up"))
8692           {
8693             aCams[anIndex]->SetUp (anXYZ);
8694           }
8695         }
8696         else
8697         {
8698           anArgIter = aViewArgIter - 1;
8699           break;
8700         }
8701       }
8702       if (!isTrsfSet)
8703       {
8704         Message::SendFail() << "Syntax error at " << anArg;
8705         return 1;
8706       }
8707       else if (aViewArgIter >= theArgNb)
8708       {
8709         anArgIter = theArgNb;
8710       }
8711
8712       aCamAnimation->SetCameraStart(aCams[0]);
8713       aCamAnimation->SetCameraEnd  (aCams[1]);
8714     }
8715     else
8716     {
8717       Message::SendFail() << "Syntax error at " << anArg;
8718       return 1;
8719     }
8720   }
8721
8722   if (!toPlay && aRecFile.IsEmpty())
8723   {
8724     return 0;
8725   }
8726
8727   // Start animation timeline and process frame updating.
8728   TheIsAnimating = Standard_True;
8729   const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
8730   Handle(Graphic3d_Camera) aCameraBack = new Graphic3d_Camera (aView->Camera());
8731   anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
8732   if (isFreeCamera)
8733   {
8734     aView->Camera()->Copy (aCameraBack);
8735   }
8736
8737   const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
8738   if (aRecParams.FpsNum <= 0)
8739   {
8740     while (!anAnimation->IsStopped())
8741     {
8742       aCameraBack->Copy (aView->Camera());
8743       const Standard_Real aPts = anAnimation->UpdateTimer();
8744       if (isFreeCamera)
8745       {
8746         aView->Camera()->Copy (aCameraBack);
8747       }
8748
8749       if (aPts >= anUpperPts)
8750       {
8751         anAnimation->Pause();
8752         break;
8753       }
8754
8755       if (aView->IsInvalidated())
8756       {
8757         aView->Redraw();
8758       }
8759       else
8760       {
8761         aView->RedrawImmediate();
8762       }
8763
8764       if (!isLockLoop)
8765       {
8766         // handle user events
8767         theDI.Eval ("after 1 set waiter 1");
8768         theDI.Eval ("vwait waiter");
8769       }
8770       if (!TheIsAnimating)
8771       {
8772         anAnimation->Pause();
8773         theDI << aPts;
8774         break;
8775       }
8776     }
8777
8778     if (aView->IsInvalidated())
8779     {
8780       aView->Redraw();
8781     }
8782     else
8783     {
8784       aView->RedrawImmediate();
8785     }
8786   }
8787   else
8788   {
8789     OSD_Timer aPerfTimer;
8790     aPerfTimer.Start();
8791
8792     Handle(Image_VideoRecorder) aRecorder;
8793     ImageFlipper aFlipper;
8794     Handle(Draw_ProgressIndicator) aProgress;
8795     if (!aRecFile.IsEmpty())
8796     {
8797       if (aRecParams.Width  <= 0
8798        || aRecParams.Height <= 0)
8799       {
8800         aView->Window()->Size (aRecParams.Width, aRecParams.Height);
8801       }
8802
8803       aRecorder = new Image_VideoRecorder();
8804       if (!aRecorder->Open (aRecFile.ToCString(), aRecParams))
8805       {
8806         Message::SendFail ("Error: failed to open video file for recording");
8807         return 0;
8808       }
8809
8810       aProgress = new Draw_ProgressIndicator (theDI, 1);
8811     }
8812
8813     // Manage frame-rated animation here
8814     Standard_Real aPts = aPlayStartTime;
8815     int64_t aNbFrames = 0;
8816     Message_ProgressScope aPS(Message_ProgressIndicator::Start(aProgress),
8817                               "Video recording, sec", Max(1, Standard_Integer(aPlayDuration / aPlaySpeed)));
8818     Standard_Integer aSecondsProgress = 0;
8819     for (; aPts <= anUpperPts && aPS.More();)
8820     {
8821       const Standard_Real aRecPts = aPlaySpeed * ((Standard_Real(aRecParams.FpsDen) / Standard_Real(aRecParams.FpsNum)) * Standard_Real(aNbFrames));
8822       aPts = aPlayStartTime + aRecPts;
8823       ++aNbFrames;
8824       if (!anAnimation->Update (aPts))
8825       {
8826         break;
8827       }
8828
8829       if (!aRecorder.IsNull())
8830       {
8831         V3d_ImageDumpOptions aDumpParams;
8832         aDumpParams.Width          = aRecParams.Width;
8833         aDumpParams.Height         = aRecParams.Height;
8834         aDumpParams.BufferType     = Graphic3d_BT_RGBA;
8835         aDumpParams.StereoOptions  = V3d_SDO_MONO;
8836         aDumpParams.ToAdjustAspect = Standard_True;
8837         if (!aView->ToPixMap (aRecorder->ChangeFrame(), aDumpParams))
8838         {
8839           Message::SendFail ("Error: view dump is failed");
8840           return 0;
8841         }
8842         aFlipper.FlipY (aRecorder->ChangeFrame());
8843         if (!aRecorder->PushFrame())
8844         {
8845           return 0;
8846         }
8847       }
8848       else
8849       {
8850         aView->Redraw();
8851       }
8852
8853       while (aSecondsProgress < Standard_Integer(aRecPts / aPlaySpeed))
8854       {
8855         aPS.Next();
8856         ++aSecondsProgress;
8857       }
8858     }
8859
8860     aPerfTimer.Stop();
8861     anAnimation->Stop();
8862     const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
8863     theDI << "Average FPS: " << aRecFps << "\n"
8864           << "Nb. Frames: "  << Standard_Real(aNbFrames);
8865
8866     aView->Redraw();
8867   }
8868
8869   aView->SetImmediateUpdate (wasImmediateUpdate);
8870   TheIsAnimating = Standard_False;
8871   return 0;
8872 }
8873
8874
8875 //=======================================================================
8876 //function : VChangeSelected
8877 //purpose  : Adds the shape to selection or remove one from it
8878 //=======================================================================
8879 static Standard_Integer VChangeSelected (Draw_Interpretor& di,
8880                                 Standard_Integer argc,
8881                                 const char ** argv)
8882 {
8883   if(argc != 2)
8884   {
8885     di<<"Usage : " << argv[0] << " shape \n";
8886     return 1;
8887   }
8888   //get AIS_Shape:
8889   TCollection_AsciiString aName(argv[1]);
8890   Handle(AIS_InteractiveObject) anAISObject;
8891   if (!GetMapOfAIS().Find2 (aName, anAISObject)
8892     || anAISObject.IsNull())
8893   {
8894     di<<"Use 'vdisplay' before";
8895     return 1;
8896   }
8897
8898   ViewerTest::GetAISContext()->AddOrRemoveSelected(anAISObject, Standard_True);
8899   return 0;
8900 }
8901
8902 //=======================================================================
8903 //function : VNbSelected
8904 //purpose  : Returns number of selected objects
8905 //=======================================================================
8906 static Standard_Integer VNbSelected (Draw_Interpretor& di,
8907                                 Standard_Integer argc,
8908                                 const char ** argv)
8909 {
8910   if(argc != 1)
8911   {
8912     di << "Usage : " << argv[0] << "\n";
8913     return 1;
8914   }
8915   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8916   if(aContext.IsNull())
8917   {
8918     di << "use 'vinit' command before " << argv[0] << "\n";
8919     return 1;
8920   }
8921   di << aContext->NbSelected() << "\n";
8922   return 0;
8923 }
8924
8925 //=======================================================================
8926 //function : VPurgeDisplay
8927 //purpose  : Switches altialiasing on or off
8928 //=======================================================================
8929 static Standard_Integer VPurgeDisplay (Draw_Interpretor& di,
8930                                 Standard_Integer argc,
8931                                 const char ** argv)
8932 {
8933   if (argc > 1)
8934   {
8935     di << "Usage : " << argv[0] << "\n";
8936     return 1;
8937   }
8938   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8939   if (aContext.IsNull())
8940   {
8941     di << "use 'vinit' command before " << argv[0] << "\n";
8942     return 1;
8943   }
8944
8945   di << aContext->PurgeDisplay() << "\n";
8946   return 0;
8947 }
8948
8949 //=======================================================================
8950 //function : VSetViewSize
8951 //purpose  :
8952 //=======================================================================
8953 static Standard_Integer VSetViewSize (Draw_Interpretor& di,
8954                                 Standard_Integer argc,
8955                                 const char ** argv)
8956 {
8957   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8958   if(aContext.IsNull())
8959   {
8960     di << "use 'vinit' command before " << argv[0] << "\n";
8961     return 1;
8962   }
8963   if(argc != 2)
8964   {
8965     di<<"Usage : " << argv[0] << " Size\n";
8966     return 1;
8967   }
8968   Standard_Real aSize = Draw::Atof (argv[1]);
8969   if (aSize <= 0.)
8970   {
8971     di<<"Bad Size value  : " << aSize << "\n";
8972     return 1;
8973   }
8974
8975   Handle(V3d_View) aView = ViewerTest::CurrentView();
8976   aView->SetSize(aSize);
8977   return 0;
8978 }
8979
8980 //=======================================================================
8981 //function : VMoveView
8982 //purpose  :
8983 //=======================================================================
8984 static Standard_Integer VMoveView (Draw_Interpretor& di,
8985                                 Standard_Integer argc,
8986                                 const char ** argv)
8987 {
8988   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
8989   if(aContext.IsNull())
8990   {
8991     di << "use 'vinit' command before " << argv[0] << "\n";
8992     return 1;
8993   }
8994   if(argc < 4 || argc > 5)
8995   {
8996     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
8997     return 1;
8998   }
8999   Standard_Real Dx = Draw::Atof (argv[1]);
9000   Standard_Real Dy = Draw::Atof (argv[2]);
9001   Standard_Real Dz = Draw::Atof (argv[3]);
9002   Standard_Boolean aStart = Standard_True;
9003   if (argc == 5)
9004   {
9005       aStart = (Draw::Atoi (argv[4]) > 0);
9006   }
9007
9008   Handle(V3d_View) aView = ViewerTest::CurrentView();
9009   aView->Move(Dx,Dy,Dz,aStart);
9010   return 0;
9011 }
9012
9013 //=======================================================================
9014 //function : VTranslateView
9015 //purpose  :
9016 //=======================================================================
9017 static Standard_Integer VTranslateView (Draw_Interpretor& di,
9018                                 Standard_Integer argc,
9019                                 const char ** argv)
9020 {
9021   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
9022   if(aContext.IsNull())
9023   {
9024     di << "use 'vinit' command before " << argv[0] << "\n";
9025     return 1;
9026   }
9027   if(argc < 4 || argc > 5)
9028   {
9029     di<<"Usage : " << argv[0] << " Dx Dy Dz [Start = 1|0]\n";
9030     return 1;
9031   }
9032   Standard_Real Dx = Draw::Atof (argv[1]);
9033   Standard_Real Dy = Draw::Atof (argv[2]);
9034   Standard_Real Dz = Draw::Atof (argv[3]);
9035   Standard_Boolean aStart = Standard_True;
9036   if (argc == 5)
9037   {
9038       aStart = (Draw::Atoi (argv[4]) > 0);
9039   }
9040
9041   Handle(V3d_View) aView = ViewerTest::CurrentView();
9042   aView->Translate(Dx,Dy,Dz,aStart);
9043   return 0;
9044 }
9045
9046 //=======================================================================
9047 //function : VTurnView
9048 //purpose  :
9049 //=======================================================================
9050 static Standard_Integer VTurnView (Draw_Interpretor& di,
9051                                 Standard_Integer argc,
9052                                 const char ** argv)
9053 {
9054   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
9055   if(aContext.IsNull()) {
9056     di << "use 'vinit' command before " << argv[0] << "\n";
9057     return 1;
9058   }
9059   if(argc < 4 || argc > 5){
9060     di<<"Usage : " << argv[0] << " Ax Ay Az [Start = 1|0]\n";
9061     return 1;
9062   }
9063   Standard_Real Ax = Draw::Atof (argv[1]);
9064   Standard_Real Ay = Draw::Atof (argv[2]);
9065   Standard_Real Az = Draw::Atof (argv[3]);
9066   Standard_Boolean aStart = Standard_True;
9067   if (argc == 5)
9068   {
9069       aStart = (Draw::Atoi (argv[4]) > 0);
9070   }
9071
9072   Handle(V3d_View) aView = ViewerTest::CurrentView();
9073   aView->Turn(Ax,Ay,Az,aStart);
9074   return 0;
9075 }
9076
9077 //==============================================================================
9078 //function : VTextureEnv
9079 //purpose  : ENables or disables environment mapping
9080 //==============================================================================
9081 class OCC_TextureEnv : public Graphic3d_TextureEnv
9082 {
9083 public:
9084   OCC_TextureEnv(const Standard_CString FileName);
9085   OCC_TextureEnv(const Graphic3d_NameOfTextureEnv aName);
9086   void SetTextureParameters(const Standard_Boolean theRepeatFlag,
9087                             const Standard_Boolean theModulateFlag,
9088                             const Graphic3d_TypeOfTextureFilter theFilter,
9089                             const Standard_ShortReal theXScale,
9090                             const Standard_ShortReal theYScale,
9091                             const Standard_ShortReal theXShift,
9092                             const Standard_ShortReal theYShift,
9093                             const Standard_ShortReal theAngle);
9094   DEFINE_STANDARD_RTTI_INLINE(OCC_TextureEnv,Graphic3d_TextureEnv)
9095 };
9096 DEFINE_STANDARD_HANDLE(OCC_TextureEnv, Graphic3d_TextureEnv)
9097
9098 OCC_TextureEnv::OCC_TextureEnv(const Standard_CString theFileName)
9099   : Graphic3d_TextureEnv(theFileName)
9100 {
9101 }
9102
9103 OCC_TextureEnv::OCC_TextureEnv(const Graphic3d_NameOfTextureEnv theTexId)
9104   : Graphic3d_TextureEnv(theTexId)
9105 {
9106 }
9107
9108 void OCC_TextureEnv::SetTextureParameters(const Standard_Boolean theRepeatFlag,
9109                                           const Standard_Boolean theModulateFlag,
9110                                           const Graphic3d_TypeOfTextureFilter theFilter,
9111                                           const Standard_ShortReal theXScale,
9112                                           const Standard_ShortReal theYScale,
9113                                           const Standard_ShortReal theXShift,
9114                                           const Standard_ShortReal theYShift,
9115                                           const Standard_ShortReal theAngle)
9116 {
9117   myParams->SetRepeat     (theRepeatFlag);
9118   myParams->SetModulate   (theModulateFlag);
9119   myParams->SetFilter     (theFilter);
9120   myParams->SetScale      (Graphic3d_Vec2(theXScale, theYScale));
9121   myParams->SetTranslation(Graphic3d_Vec2(theXShift, theYShift));
9122   myParams->SetRotation   (theAngle);
9123 }
9124
9125 static int VTextureEnv (Draw_Interpretor& /*theDI*/, Standard_Integer theArgNb, const char** theArgVec)
9126 {
9127   // get the active view
9128   Handle(V3d_View) aView = ViewerTest::CurrentView();
9129   if (aView.IsNull())
9130   {
9131     Message::SendFail ("Error: no active viewer");
9132     return 1;
9133   }
9134
9135   // Checking the input arguments
9136   Standard_Boolean anEnableFlag = Standard_False;
9137   Standard_Boolean isOk         = theArgNb >= 2;
9138   if (isOk)
9139   {
9140     TCollection_AsciiString anEnableOpt(theArgVec[1]);
9141     anEnableFlag = anEnableOpt.IsEqual("on");
9142     isOk         = anEnableFlag || anEnableOpt.IsEqual("off");
9143   }
9144   if (anEnableFlag)
9145   {
9146     isOk = (theArgNb == 3 || theArgNb == 11);
9147     if (isOk)
9148     {
9149       TCollection_AsciiString aTextureOpt(theArgVec[2]);
9150       isOk = (!aTextureOpt.IsIntegerValue() ||
9151              (aTextureOpt.IntegerValue() >= 0 && aTextureOpt.IntegerValue() < Graphic3d_NOT_ENV_UNKNOWN));
9152
9153       if (isOk && theArgNb == 11)
9154       {
9155         TCollection_AsciiString aRepeatOpt  (theArgVec[3]),
9156                                 aModulateOpt(theArgVec[4]),
9157                                 aFilterOpt  (theArgVec[5]),
9158                                 aSScaleOpt  (theArgVec[6]),
9159                                 aTScaleOpt  (theArgVec[7]),
9160                                 aSTransOpt  (theArgVec[8]),
9161                                 aTTransOpt  (theArgVec[9]),
9162                                 anAngleOpt  (theArgVec[10]);
9163         isOk = ((aRepeatOpt.  IsEqual("repeat")   || aRepeatOpt.  IsEqual("clamp")) &&
9164                 (aModulateOpt.IsEqual("modulate") || aModulateOpt.IsEqual("decal")) &&
9165                 (aFilterOpt.  IsEqual("nearest")  || aFilterOpt.  IsEqual("bilinear") || aFilterOpt.IsEqual("trilinear")) &&
9166                 aSScaleOpt.IsRealValue (Standard_True) && aTScaleOpt.IsRealValue (Standard_True) &&
9167                 aSTransOpt.IsRealValue (Standard_True) && aTTransOpt.IsRealValue (Standard_True) &&
9168                 anAngleOpt.IsRealValue (Standard_True));
9169       }
9170     }
9171   }
9172
9173   if (!isOk)
9174   {
9175     Message::SendFail() << "Usage:\n"
9176                         << theArgVec[0] << " off\n"
9177                         << 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]";
9178     return 1;
9179   }
9180
9181   if (anEnableFlag)
9182   {
9183     TCollection_AsciiString aTextureOpt(theArgVec[2]);
9184     Handle(OCC_TextureEnv) aTexEnv = aTextureOpt.IsIntegerValue() ?
9185                                      new OCC_TextureEnv((Graphic3d_NameOfTextureEnv)aTextureOpt.IntegerValue()) :
9186                                      new OCC_TextureEnv(theArgVec[2]);
9187
9188     if (theArgNb == 11)
9189     {
9190       TCollection_AsciiString aRepeatOpt(theArgVec[3]), aModulateOpt(theArgVec[4]), aFilterOpt(theArgVec[5]);
9191       aTexEnv->SetTextureParameters(
9192         aRepeatOpt.  IsEqual("repeat"),
9193         aModulateOpt.IsEqual("modulate"),
9194         aFilterOpt.  IsEqual("nearest") ? Graphic3d_TOTF_NEAREST :
9195                                           aFilterOpt.IsEqual("bilinear") ? Graphic3d_TOTF_BILINEAR :
9196                                                                            Graphic3d_TOTF_TRILINEAR,
9197         (Standard_ShortReal)Draw::Atof(theArgVec[6]),
9198         (Standard_ShortReal)Draw::Atof(theArgVec[7]),
9199         (Standard_ShortReal)Draw::Atof(theArgVec[8]),
9200         (Standard_ShortReal)Draw::Atof(theArgVec[9]),
9201         (Standard_ShortReal)Draw::Atof(theArgVec[10])
9202         );
9203     }
9204     aView->SetTextureEnv(aTexEnv);
9205   }
9206   else // Disabling environment mapping
9207   {
9208     Handle(Graphic3d_TextureEnv) aTexture;
9209     aView->SetTextureEnv(aTexture); // Passing null handle to clear the texture data
9210   }
9211
9212   aView->Redraw();
9213   return 0;
9214 }
9215
9216 namespace
9217 {
9218   typedef NCollection_DataMap<TCollection_AsciiString, Handle(Graphic3d_ClipPlane)> MapOfPlanes;
9219
9220   //! Remove registered clipping plane from all views and objects.
9221   static void removePlane (MapOfPlanes& theRegPlanes,
9222                            const TCollection_AsciiString& theName)
9223   {
9224     Handle(Graphic3d_ClipPlane) aClipPlane;
9225     if (!theRegPlanes.Find (theName, aClipPlane))
9226     {
9227       Message::SendWarning ("Warning: no such plane");
9228       return;
9229     }
9230
9231     theRegPlanes.UnBind (theName);
9232     for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIObjIt (GetMapOfAIS());
9233          anIObjIt.More(); anIObjIt.Next())
9234     {
9235       const Handle(AIS_InteractiveObject)& aPrs = anIObjIt.Key1();
9236       aPrs->RemoveClipPlane (aClipPlane);
9237     }
9238
9239     for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
9240          aViewIt.More(); aViewIt.Next())
9241     {
9242       const Handle(V3d_View)& aView = aViewIt.Key2();
9243       aView->RemoveClipPlane(aClipPlane);
9244     }
9245
9246     ViewerTest::RedrawAllViews();
9247   }
9248 }
9249
9250 //===============================================================================================
9251 //function : VClipPlane
9252 //purpose  :
9253 //===============================================================================================
9254 static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9255 {
9256   // use short-cut for created clip planes map of created (or "registered by name") clip planes
9257   static MapOfPlanes aRegPlanes;
9258
9259   if (theArgsNb < 2)
9260   {
9261     for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More(); aPlaneIter.Next())
9262     {
9263       theDi << aPlaneIter.Key() << " ";
9264     }
9265     return 0;
9266   }
9267
9268   TCollection_AsciiString aCommand (theArgVec[1]);
9269   aCommand.LowerCase();
9270   const Handle(V3d_View)& anActiveView = ViewerTest::CurrentView();
9271   if (anActiveView.IsNull())
9272   {
9273     Message::SendFail ("Error: no active viewer");
9274     return 1;
9275   }
9276
9277   // print maximum number of planes for current viewer
9278   if (aCommand == "-maxplanes"
9279    || aCommand == "maxplanes")
9280   {
9281     theDi << anActiveView->Viewer()->Driver()->InquirePlaneLimit()
9282           << " plane slots provided by driver.\n";
9283     return 0;
9284   }
9285
9286   // create / delete plane instance
9287   if (aCommand == "-create"
9288    || aCommand == "create"
9289    || aCommand == "-delete"
9290    || aCommand == "delete"
9291    || aCommand == "-clone"
9292    || aCommand == "clone")
9293   {
9294     if (theArgsNb < 3)
9295     {
9296       Message::SendFail ("Syntax error: plane name is required");
9297       return 1;
9298     }
9299
9300     Standard_Boolean toCreate = aCommand == "-create"
9301                              || aCommand == "create";
9302     Standard_Boolean toClone  = aCommand == "-clone"
9303                              || aCommand == "clone";
9304     Standard_Boolean toDelete = aCommand == "-delete"
9305                              || aCommand == "delete";
9306     TCollection_AsciiString aPlane (theArgVec[2]);
9307
9308     if (toCreate)
9309     {
9310       if (aRegPlanes.IsBound (aPlane))
9311       {
9312         std::cout << "Warning: existing plane has been overridden.\n";
9313         toDelete = true;
9314       }
9315       else
9316       {
9317         aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9318         return 0;
9319       }
9320     }
9321     else if (toClone) // toClone
9322     {
9323       if (!aRegPlanes.IsBound (aPlane))
9324       {
9325         Message::SendFail ("Error: no such plane");
9326         return 1;
9327       }
9328       else if (theArgsNb < 4)
9329       {
9330         Message::SendFail ("Syntax error: enter name for new plane");
9331         return 1;
9332       }
9333
9334       TCollection_AsciiString aClone (theArgVec[3]);
9335       if (aRegPlanes.IsBound (aClone))
9336       {
9337         Message::SendFail ("Error: plane name is in use");
9338         return 1;
9339       }
9340
9341       const Handle(Graphic3d_ClipPlane)& aClipPlane = aRegPlanes.Find (aPlane);
9342
9343       aRegPlanes.Bind (aClone, aClipPlane->Clone());
9344       return 0;
9345     }
9346
9347     if (toDelete)
9348     {
9349       if (aPlane == "ALL"
9350        || aPlane == "all"
9351        || aPlane == "*")
9352       {
9353         for (MapOfPlanes::Iterator aPlaneIter (aRegPlanes); aPlaneIter.More();)
9354         {
9355           aPlane = aPlaneIter.Key();
9356           removePlane (aRegPlanes, aPlane);
9357           aPlaneIter = MapOfPlanes::Iterator (aRegPlanes);
9358         }
9359       }
9360       else
9361       {
9362         removePlane (aRegPlanes, aPlane);
9363       }
9364     }
9365
9366     if (toCreate)
9367     {
9368       aRegPlanes.Bind (aPlane, new Graphic3d_ClipPlane());
9369     }
9370     return 0;
9371   }
9372
9373   // set / unset plane command
9374   if (aCommand == "set"
9375    || aCommand == "unset")
9376   {
9377     if (theArgsNb < 5)
9378     {
9379       Message::SendFail ("Syntax error: need more arguments");
9380       return 1;
9381     }
9382
9383     // redirect to new syntax
9384     NCollection_Array1<const char*> anArgVec (1, theArgsNb - 1);
9385     anArgVec.SetValue (1, theArgVec[0]);
9386     anArgVec.SetValue (2, theArgVec[2]);
9387     anArgVec.SetValue (3, aCommand == "set" ? "-set" : "-unset");
9388     for (Standard_Integer anIt = 4; anIt < theArgsNb; ++anIt)
9389     {
9390       anArgVec.SetValue (anIt, theArgVec[anIt]);
9391     }
9392
9393     return VClipPlane (theDi, anArgVec.Length(), &anArgVec.ChangeFirst());
9394   }
9395
9396   // change plane command
9397   TCollection_AsciiString aPlaneName;
9398   Handle(Graphic3d_ClipPlane) aClipPlane;
9399   Standard_Integer anArgIter = 0;
9400   if (aCommand == "-change"
9401    || aCommand == "change")
9402   {
9403     // old syntax support
9404     if (theArgsNb < 3)
9405     {
9406       Message::SendFail ("Syntax error: need more arguments");
9407       return 1;
9408     }
9409
9410     anArgIter  = 3;
9411     aPlaneName = theArgVec[2];
9412     if (!aRegPlanes.Find (aPlaneName, aClipPlane))
9413     {
9414       Message::SendFail() << "Error: no such plane '" << aPlaneName << "'";
9415       return 1;
9416     }
9417   }
9418   else if (aRegPlanes.Find (theArgVec[1], aClipPlane))
9419   {
9420     anArgIter  = 2;
9421     aPlaneName = theArgVec[1];
9422   }
9423   else
9424   {
9425     anArgIter  = 2;
9426     aPlaneName = theArgVec[1];
9427     aClipPlane = new Graphic3d_ClipPlane();
9428     aRegPlanes.Bind (aPlaneName, aClipPlane);
9429     theDi << "Created new plane " << aPlaneName << ".\n";
9430   }
9431
9432   if (theArgsNb - anArgIter < 1)
9433   {
9434     Message::SendFail ("Syntax error: need more arguments");
9435     return 1;
9436   }
9437
9438   for (; anArgIter < theArgsNb; ++anArgIter)
9439   {
9440     const char**     aChangeArgs   = theArgVec + anArgIter;
9441     Standard_Integer aNbChangeArgs = theArgsNb - anArgIter;
9442     TCollection_AsciiString aChangeArg (aChangeArgs[0]);
9443     aChangeArg.LowerCase();
9444
9445     Standard_Boolean toEnable = Standard_True;
9446     if (Draw::ParseOnOff (aChangeArgs[0], toEnable))
9447     {
9448       aClipPlane->SetOn (toEnable);
9449     }
9450     else if (aChangeArg.StartsWith ("-equation")
9451           || aChangeArg.StartsWith ("equation"))
9452     {
9453       if (aNbChangeArgs < 5)
9454       {
9455         Message::SendFail ("Syntax error: need more arguments");
9456         return 1;
9457       }
9458
9459       Standard_Integer aSubIndex = 1;
9460       Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0);
9461       if (aPrefixLen < aChangeArg.Length())
9462       {
9463         TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length());
9464         if (!aSubStr.IsIntegerValue()
9465           || aSubStr.IntegerValue() <= 0)
9466         {
9467           Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9468           return 1;
9469         }
9470         aSubIndex = aSubStr.IntegerValue();
9471       }
9472
9473       Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]);
9474       Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]);
9475       Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]);
9476       Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]);
9477       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9478       for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter)
9479       {
9480         if (aSubPln->ChainNextPlane().IsNull())
9481         {
9482           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9483         }
9484         aSubPln = aSubPln->ChainNextPlane();
9485       }
9486       aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9487       aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD));
9488       anArgIter += 4;
9489     }
9490     else if ((aChangeArg == "-boxinterior"
9491            || aChangeArg == "-boxint"
9492            || aChangeArg == "-box")
9493             && aNbChangeArgs >= 7)
9494     {
9495       Graphic3d_BndBox3d aBndBox;
9496       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3])));
9497       aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6])));
9498       anArgIter += 6;
9499
9500       Standard_Integer aNbSubPlanes = 6;
9501       const Graphic3d_Vec3d aDirArray[6] =
9502       {
9503         Graphic3d_Vec3d (-1, 0, 0),
9504         Graphic3d_Vec3d ( 1, 0, 0),
9505         Graphic3d_Vec3d ( 0,-1, 0),
9506         Graphic3d_Vec3d ( 0, 1, 0),
9507         Graphic3d_Vec3d ( 0, 0,-1),
9508         Graphic3d_Vec3d ( 0, 0, 1),
9509       };
9510       Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane;
9511       for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter)
9512       {
9513         const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter];
9514         const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin());
9515         aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW));
9516         if (aSubPlaneIter + 1 == aNbSubPlanes)
9517         {
9518           aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)());
9519         }
9520         else
9521         {
9522           aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln));
9523         }
9524         aSubPln = aSubPln->ChainNextPlane();
9525       }
9526     }
9527     else if (aChangeArg == "-capping"
9528           || aChangeArg == "capping")
9529     {
9530       if (aNbChangeArgs < 2)
9531       {
9532         Message::SendFail ("Syntax error: need more arguments");
9533         return 1;
9534       }
9535
9536       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9537       {
9538         aClipPlane->SetCapping (toEnable);
9539         anArgIter += 1;
9540       }
9541       else
9542       {
9543         // just skip otherwise (old syntax)
9544       }
9545     }
9546     else if (aChangeArg == "-useobjectmaterial"
9547           || aChangeArg == "-useobjectmat"
9548           || aChangeArg == "-useobjmat"
9549           || aChangeArg == "-useobjmaterial")
9550     {
9551       if (aNbChangeArgs < 2)
9552       {
9553         Message::SendFail ("Syntax error: need more arguments");
9554         return 1;
9555       }
9556
9557       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9558       {
9559         aClipPlane->SetUseObjectMaterial (toEnable == Standard_True);
9560         anArgIter += 1;
9561       }
9562     }
9563     else if (aChangeArg == "-useobjecttexture"
9564           || aChangeArg == "-useobjecttex"
9565           || aChangeArg == "-useobjtexture"
9566           || aChangeArg == "-useobjtex")
9567     {
9568       if (aNbChangeArgs < 2)
9569       {
9570         Message::SendFail ("Syntax error: need more arguments");
9571         return 1;
9572       }
9573
9574       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9575       {
9576         aClipPlane->SetUseObjectTexture (toEnable == Standard_True);
9577         anArgIter += 1;
9578       }
9579     }
9580     else if (aChangeArg == "-useobjectshader"
9581           || aChangeArg == "-useobjshader")
9582     {
9583       if (aNbChangeArgs < 2)
9584       {
9585         Message::SendFail ("Syntax error: need more arguments");
9586         return 1;
9587       }
9588
9589       if (Draw::ParseOnOff (aChangeArgs[1], toEnable))
9590       {
9591         aClipPlane->SetUseObjectShader (toEnable == Standard_True);
9592         anArgIter += 1;
9593       }
9594     }
9595     else if (aChangeArg == "-color"
9596           || aChangeArg == "color")
9597     {
9598       Quantity_Color aColor;
9599       Standard_Integer aNbParsed = Draw::ParseColor (aNbChangeArgs - 1,
9600                                                      aChangeArgs + 1,
9601                                                      aColor);
9602       if (aNbParsed == 0)
9603       {
9604         Message::SendFail ("Syntax error: need more arguments");
9605         return 1;
9606       }
9607       aClipPlane->SetCappingColor (aColor);
9608       anArgIter += aNbParsed;
9609     }
9610     else if (aNbChangeArgs >= 1
9611           && (aChangeArg == "-material"
9612            || aChangeArg == "material"))
9613     {
9614       ++anArgIter;
9615       Graphic3d_NameOfMaterial aMatName;
9616       if (!Graphic3d_MaterialAspect::MaterialFromName (aChangeArgs[1], aMatName))
9617       {
9618         Message::SendFail() << "Syntax error: unknown material '" << aChangeArgs[1] << "'";
9619         return 1;
9620       }
9621       aClipPlane->SetCappingMaterial (aMatName);
9622     }
9623     else if ((aChangeArg == "-transparency"
9624            || aChangeArg == "-transp")
9625           && aNbChangeArgs >= 2)
9626     {
9627       TCollection_AsciiString aValStr (aChangeArgs[1]);
9628       Handle(Graphic3d_AspectFillArea3d) anAspect = aClipPlane->CappingAspect();
9629       if (aValStr.IsRealValue (Standard_True))
9630       {
9631         Graphic3d_MaterialAspect aMat = aClipPlane->CappingMaterial();
9632         aMat.SetTransparency ((float )aValStr.RealValue());
9633         anAspect->SetAlphaMode (Graphic3d_AlphaMode_BlendAuto);
9634         aClipPlane->SetCappingMaterial (aMat);
9635       }
9636       else
9637       {
9638         aValStr.LowerCase();
9639         Graphic3d_AlphaMode aMode = Graphic3d_AlphaMode_BlendAuto;
9640         if (aValStr == "opaque")
9641         {
9642           aMode = Graphic3d_AlphaMode_Opaque;
9643         }
9644         else if (aValStr == "mask")
9645         {
9646           aMode = Graphic3d_AlphaMode_Mask;
9647         }
9648         else if (aValStr == "blend")
9649         {
9650           aMode = Graphic3d_AlphaMode_Blend;
9651         }
9652         else if (aValStr == "blendauto")
9653         {
9654           aMode = Graphic3d_AlphaMode_BlendAuto;
9655         }
9656         else
9657         {
9658           Message::SendFail() << "Syntax error at '" << aValStr << "'";
9659           return 1;
9660         }
9661         anAspect->SetAlphaMode (aMode);
9662         aClipPlane->SetCappingAspect (anAspect);
9663       }
9664       anArgIter += 1;
9665     }
9666     else if (aChangeArg == "-texname"
9667           || aChangeArg == "texname")
9668     {
9669       if (aNbChangeArgs < 2)
9670       {
9671         Message::SendFail ("Syntax error: need more arguments");
9672         return 1;
9673       }
9674
9675       TCollection_AsciiString aTextureName (aChangeArgs[1]);
9676       Handle(Graphic3d_Texture2Dmanual) aTexture = new Graphic3d_Texture2Dmanual(aTextureName);
9677       if (!aTexture->IsDone())
9678       {
9679         aClipPlane->SetCappingTexture (NULL);
9680       }
9681       else
9682       {
9683         aTexture->EnableModulate();
9684         aTexture->EnableRepeat();
9685         aClipPlane->SetCappingTexture (aTexture);
9686       }
9687       anArgIter += 1;
9688     }
9689     else if (aChangeArg == "-texscale"
9690           || aChangeArg == "texscale")
9691     {
9692       if (aClipPlane->CappingTexture().IsNull())
9693       {
9694         Message::SendFail ("Error: no texture is set");
9695         return 1;
9696       }
9697
9698       if (aNbChangeArgs < 3)
9699       {
9700         Message::SendFail ("Syntax error: need more arguments");
9701         return 1;
9702       }
9703
9704       Standard_ShortReal aSx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9705       Standard_ShortReal aSy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9706       aClipPlane->CappingTexture()->GetParams()->SetScale (Graphic3d_Vec2 (aSx, aSy));
9707       anArgIter += 2;
9708     }
9709     else if (aChangeArg == "-texorigin"
9710           || aChangeArg == "texorigin") // texture origin
9711     {
9712       if (aClipPlane->CappingTexture().IsNull())
9713       {
9714         Message::SendFail ("Error: no texture is set");
9715         return 1;
9716       }
9717
9718       if (aNbChangeArgs < 3)
9719       {
9720         Message::SendFail ("Syntax error: need more arguments");
9721         return 1;
9722       }
9723
9724       Standard_ShortReal aTx = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9725       Standard_ShortReal aTy = (Standard_ShortReal)Draw::Atof (aChangeArgs[2]);
9726
9727       aClipPlane->CappingTexture()->GetParams()->SetTranslation (Graphic3d_Vec2 (aTx, aTy));
9728       anArgIter += 2;
9729     }
9730     else if (aChangeArg == "-texrotate"
9731           || aChangeArg == "texrotate") // texture rotation
9732     {
9733       if (aClipPlane->CappingTexture().IsNull())
9734       {
9735         Message::SendFail ("Error: no texture is set");
9736         return 1;
9737       }
9738
9739       if (aNbChangeArgs < 2)
9740       {
9741         Message::SendFail ("Syntax error: need more arguments");
9742         return 1;
9743       }
9744
9745       Standard_ShortReal aRot = (Standard_ShortReal)Draw::Atof (aChangeArgs[1]);
9746       aClipPlane->CappingTexture()->GetParams()->SetRotation (aRot);
9747       anArgIter += 1;
9748     }
9749     else if (aChangeArg == "-hatch"
9750           || aChangeArg == "hatch")
9751     {
9752       if (aNbChangeArgs < 2)
9753       {
9754         Message::SendFail ("Syntax error: need more arguments");
9755         return 1;
9756       }
9757
9758       TCollection_AsciiString aHatchStr (aChangeArgs[1]);
9759       aHatchStr.LowerCase();
9760       if (aHatchStr == "on")
9761       {
9762         aClipPlane->SetCappingHatchOn();
9763       }
9764       else if (aHatchStr == "off")
9765       {
9766         aClipPlane->SetCappingHatchOff();
9767       }
9768       else
9769       {
9770         aClipPlane->SetCappingHatch ((Aspect_HatchStyle)Draw::Atoi (aChangeArgs[1]));
9771       }
9772       anArgIter += 1;
9773     }
9774     else if (aChangeArg == "-delete"
9775           || aChangeArg == "delete")
9776     {
9777       removePlane (aRegPlanes, aPlaneName);
9778       return 0;
9779     }
9780     else if (aChangeArg == "-set"
9781           || aChangeArg == "-unset"
9782           || aChangeArg == "-setoverrideglobal")
9783     {
9784       // set / unset plane command
9785       const Standard_Boolean toSet            = aChangeArg.StartsWith ("-set");
9786       const Standard_Boolean toOverrideGlobal = aChangeArg == "-setoverrideglobal";
9787       Standard_Integer anIt = 1;
9788       for (; anIt < aNbChangeArgs; ++anIt)
9789       {
9790         TCollection_AsciiString anEntityName (aChangeArgs[anIt]);
9791         if (anEntityName.IsEmpty()
9792          || anEntityName.Value (1) == '-')
9793         {
9794           break;
9795         }
9796         else if (!toOverrideGlobal
9797                && ViewerTest_myViews.IsBound1 (anEntityName))
9798         {
9799           Handle(V3d_View) aView = ViewerTest_myViews.Find1 (anEntityName);
9800           if (toSet)
9801           {
9802             aView->AddClipPlane (aClipPlane);
9803           }
9804           else
9805           {
9806             aView->RemoveClipPlane (aClipPlane);
9807           }
9808           continue;
9809         }
9810         else if (GetMapOfAIS().IsBound2 (anEntityName))
9811         {
9812           Handle(AIS_InteractiveObject) aIObj = GetMapOfAIS().Find2 (anEntityName);
9813           if (toSet)
9814           {
9815             aIObj->AddClipPlane (aClipPlane);
9816           }
9817           else
9818           {
9819             aIObj->RemoveClipPlane (aClipPlane);
9820           }
9821           if (!aIObj->ClipPlanes().IsNull())
9822           {
9823             aIObj->ClipPlanes()->SetOverrideGlobal (toOverrideGlobal);
9824           }
9825         }
9826         else
9827         {
9828           Message::SendFail() << "Error: object/view '" << anEntityName << "' is not found";
9829           return 1;
9830         }
9831       }
9832
9833       if (anIt == 1)
9834       {
9835         // apply to active view
9836         if (toSet)
9837         {
9838           anActiveView->AddClipPlane (aClipPlane);
9839         }
9840         else
9841         {
9842           anActiveView->RemoveClipPlane (aClipPlane);
9843         }
9844       }
9845       else
9846       {
9847         anArgIter = anArgIter + anIt - 1;
9848       }
9849     }
9850     else
9851     {
9852       Message::SendFail() << "Syntax error: unknown argument '" << aChangeArg << "'";
9853       return 1;
9854     }
9855   }
9856
9857   ViewerTest::RedrawAllViews();
9858   return 0;
9859 }
9860
9861 //===============================================================================================
9862 //function : VZRange
9863 //purpose  :
9864 //===============================================================================================
9865 static int VZRange (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9866 {
9867   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9868
9869   if (aCurrentView.IsNull())
9870   {
9871     Message::SendFail ("Error: no active viewer");
9872     return 1;
9873   }
9874
9875   Handle(Graphic3d_Camera) aCamera = aCurrentView->Camera();
9876
9877   if (theArgsNb < 2)
9878   {
9879     theDi << "ZNear: " << aCamera->ZNear() << "\n";
9880     theDi << "ZFar: " << aCamera->ZFar() << "\n";
9881     return 0;
9882   }
9883
9884   if (theArgsNb == 3)
9885   {
9886     Standard_Real aNewZNear = Draw::Atof (theArgVec[1]);
9887     Standard_Real aNewZFar  = Draw::Atof (theArgVec[2]);
9888
9889     if (aNewZNear >= aNewZFar)
9890     {
9891       Message::SendFail ("Syntax error: invalid arguments: znear should be less than zfar");
9892       return 1;
9893     }
9894
9895     if (!aCamera->IsOrthographic() && (aNewZNear <= 0.0 || aNewZFar <= 0.0))
9896     {
9897       Message::SendFail ("Syntax error: invalid arguments: znear, zfar should be positive for perspective camera");
9898       return 1;
9899     }
9900
9901     aCamera->SetZRange (aNewZNear, aNewZFar);
9902   }
9903   else
9904   {
9905     Message::SendFail ("Syntax error: wrong command arguments");
9906     return 1;
9907   }
9908
9909   aCurrentView->Redraw();
9910
9911   return 0;
9912 }
9913
9914 //===============================================================================================
9915 //function : VAutoZFit
9916 //purpose  :
9917 //===============================================================================================
9918 static int VAutoZFit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
9919 {
9920   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
9921
9922   if (aCurrentView.IsNull())
9923   {
9924     Message::SendFail ("Error: no active viewer");
9925     return 1;
9926   }
9927
9928   Standard_Real aScale = aCurrentView->AutoZFitScaleFactor();
9929
9930   if (theArgsNb > 3)
9931   {
9932     Message::SendFail ("Syntax error: wrong command arguments");
9933     return 1;
9934   }
9935
9936   if (theArgsNb < 2)
9937   {
9938     theDi << "Auto z-fit mode: \n"
9939           << "On: " << (aCurrentView->AutoZFitMode() ? "enabled" : "disabled") << "\n"
9940           << "Scale: " << aScale << "\n";
9941     return 0;
9942   }
9943
9944   Standard_Boolean isOn = Draw::Atoi (theArgVec[1]) == 1;
9945
9946   if (theArgsNb >= 3)
9947   {
9948     aScale = Draw::Atoi (theArgVec[2]);
9949   }
9950
9951   aCurrentView->SetAutoZFitMode (isOn, aScale);
9952   aCurrentView->Redraw();
9953   return 0;
9954 }
9955
9956 //! Auxiliary function to print projection type
9957 inline const char* projTypeName (Graphic3d_Camera::Projection theProjType)
9958 {
9959   switch (theProjType)
9960   {
9961     case Graphic3d_Camera::Projection_Orthographic: return "orthographic";
9962     case Graphic3d_Camera::Projection_Perspective:  return "perspective";
9963     case Graphic3d_Camera::Projection_Stereo:       return "stereoscopic";
9964     case Graphic3d_Camera::Projection_MonoLeftEye:  return "monoLeftEye";
9965     case Graphic3d_Camera::Projection_MonoRightEye: return "monoRightEye";
9966   }
9967   return "UNKNOWN";
9968 }
9969
9970 //===============================================================================================
9971 //function : VCamera
9972 //purpose  :
9973 //===============================================================================================
9974 static int VCamera (Draw_Interpretor& theDI,
9975                     Standard_Integer  theArgsNb,
9976                     const char**      theArgVec)
9977 {
9978   Handle(V3d_View) aView = ViewerTest::CurrentView();
9979   if (aView.IsNull())
9980   {
9981     Message::SendFail ("Error: no active viewer");
9982     return 1;
9983   }
9984
9985   Handle(Graphic3d_Camera) aCamera = aView->Camera();
9986   if (theArgsNb < 2)
9987   {
9988     theDI << "ProjType:   " << projTypeName (aCamera->ProjectionType()) << "\n";
9989     theDI << "FOVy:       " << aCamera->FOVy() << "\n";
9990     theDI << "FOVx:       " << aCamera->FOVx() << "\n";
9991     theDI << "FOV2d:      " << aCamera->FOV2d() << "\n";
9992     theDI << "Distance:   " << aCamera->Distance() << "\n";
9993     theDI << "IOD:        " << aCamera->IOD() << "\n";
9994     theDI << "IODType:    " << (aCamera->GetIODType() == Graphic3d_Camera::IODType_Absolute   ? "absolute" : "relative") << "\n";
9995     theDI << "ZFocus:     " << aCamera->ZFocus() << "\n";
9996     theDI << "ZFocusType: " << (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Absolute ? "absolute" : "relative") << "\n";
9997     return 0;
9998   }
9999
10000   TCollection_AsciiString aPrsName;
10001   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
10002   {
10003     Standard_CString        anArg = theArgVec[anArgIter];
10004     TCollection_AsciiString anArgCase (anArg);
10005     anArgCase.LowerCase();
10006     if (anArgCase == "-proj"
10007      || anArgCase == "-projection"
10008      || anArgCase == "-projtype"
10009      || anArgCase == "-projectiontype")
10010     {
10011       theDI << projTypeName (aCamera->ProjectionType()) << " ";
10012     }
10013     else if (anArgCase == "-ortho"
10014           || anArgCase == "-orthographic")
10015     {
10016       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
10017     }
10018     else if (anArgCase == "-persp"
10019           || anArgCase == "-perspective"
10020           || anArgCase == "-perspmono"
10021           || anArgCase == "-perspectivemono"
10022           || anArgCase == "-mono")
10023     {
10024       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10025     }
10026     else if (anArgCase == "-stereo"
10027           || anArgCase == "-stereoscopic"
10028           || anArgCase == "-perspstereo"
10029           || anArgCase == "-perspectivestereo")
10030     {
10031       aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10032     }
10033     else if (anArgCase == "-left"
10034           || anArgCase == "-lefteye"
10035           || anArgCase == "-monoleft"
10036           || anArgCase == "-monolefteye"
10037           || anArgCase == "-perpsleft"
10038           || anArgCase == "-perpslefteye")
10039     {
10040       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoLeftEye);
10041     }
10042     else if (anArgCase == "-right"
10043           || anArgCase == "-righteye"
10044           || anArgCase == "-monoright"
10045           || anArgCase == "-monorighteye"
10046           || anArgCase == "-perpsright")
10047     {
10048       aCamera->SetProjectionType (Graphic3d_Camera::Projection_MonoRightEye);
10049     }
10050     else if (anArgCase == "-dist"
10051           || anArgCase == "-distance")
10052     {
10053       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10054       if (anArgValue != NULL
10055       && *anArgValue != '-')
10056       {
10057         ++anArgIter;
10058         aCamera->SetDistance (Draw::Atof (anArgValue));
10059         continue;
10060       }
10061       theDI << aCamera->Distance() << " ";
10062     }
10063     else if (anArgCase == "-iod")
10064     {
10065       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10066       if (anArgValue != NULL
10067       && *anArgValue != '-')
10068       {
10069         ++anArgIter;
10070         aCamera->SetIOD (aCamera->GetIODType(), Draw::Atof (anArgValue));
10071         continue;
10072       }
10073       theDI << aCamera->IOD() << " ";
10074     }
10075     else if (anArgCase == "-iodtype")
10076     {
10077       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10078       TCollection_AsciiString anValueCase (anArgValue);
10079       anValueCase.LowerCase();
10080       if (anValueCase == "abs"
10081        || anValueCase == "absolute")
10082       {
10083         ++anArgIter;
10084         aCamera->SetIOD (Graphic3d_Camera::IODType_Absolute, aCamera->IOD());
10085         continue;
10086       }
10087       else if (anValueCase == "rel"
10088             || anValueCase == "relative")
10089       {
10090         ++anArgIter;
10091         aCamera->SetIOD (Graphic3d_Camera::IODType_Relative, aCamera->IOD());
10092         continue;
10093       }
10094       else if (*anArgValue != '-')
10095       {
10096         Message::SendFail() << "Error: unknown IOD type '" << anArgValue << "'";
10097         return 1;
10098       }
10099       switch (aCamera->GetIODType())
10100       {
10101         case Graphic3d_Camera::IODType_Absolute: theDI << "absolute "; break;
10102         case Graphic3d_Camera::IODType_Relative: theDI << "relative "; break;
10103       }
10104     }
10105     else if (anArgCase == "-zfocus")
10106     {
10107       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10108       if (anArgValue != NULL
10109       && *anArgValue != '-')
10110       {
10111         ++anArgIter;
10112         aCamera->SetZFocus (aCamera->ZFocusType(), Draw::Atof (anArgValue));
10113         continue;
10114       }
10115       theDI << aCamera->ZFocus() << " ";
10116     }
10117     else if (anArgCase == "-zfocustype")
10118     {
10119       Standard_CString        anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : "";
10120       TCollection_AsciiString anValueCase (anArgValue);
10121       anValueCase.LowerCase();
10122       if (anValueCase == "abs"
10123        || anValueCase == "absolute")
10124       {
10125         ++anArgIter;
10126         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Absolute, aCamera->ZFocus());
10127         continue;
10128       }
10129       else if (anValueCase == "rel"
10130             || anValueCase == "relative")
10131       {
10132         ++anArgIter;
10133         aCamera->SetZFocus (Graphic3d_Camera::FocusType_Relative, aCamera->ZFocus());
10134         continue;
10135       }
10136       else if (*anArgValue != '-')
10137       {
10138         Message::SendFail() << "Error: unknown ZFocus type '" << anArgValue << "'";
10139         return 1;
10140       }
10141       switch (aCamera->ZFocusType())
10142       {
10143         case Graphic3d_Camera::FocusType_Absolute: theDI << "absolute "; break;
10144         case Graphic3d_Camera::FocusType_Relative: theDI << "relative "; break;
10145       }
10146     }
10147     else if (anArgCase == "-lockzup"
10148           || anArgCase == "-turntable")
10149     {
10150       bool toLockUp = true;
10151       if (++anArgIter < theArgsNb
10152       && !Draw::ParseOnOff (theArgVec[anArgIter], toLockUp))
10153       {
10154         --anArgIter;
10155       }
10156       ViewerTest::CurrentEventManager()->SetLockOrbitZUp (toLockUp);
10157     }
10158     else if (anArgCase == "-fov"
10159           || anArgCase == "-fovy"
10160           || anArgCase == "-fovx"
10161           || anArgCase == "-fov2d")
10162     {
10163       Standard_CString anArgValue = (anArgIter + 1 < theArgsNb) ? theArgVec[anArgIter + 1] : NULL;
10164       if (anArgValue != NULL
10165       && *anArgValue != '-')
10166       {
10167         ++anArgIter;
10168         if (anArgCase == "-fov2d")
10169         {
10170           aCamera->SetFOV2d (Draw::Atof (anArgValue));
10171         }
10172         else if (anArgCase == "-fovx")
10173         {
10174           aCamera->SetFOVy (Draw::Atof (anArgValue) / aCamera->Aspect());///
10175         }
10176         else
10177         {
10178           aCamera->SetFOVy (Draw::Atof (anArgValue));
10179         }
10180         continue;
10181       }
10182       if (anArgCase == "-fov2d")
10183       {
10184         theDI << aCamera->FOV2d() << " ";
10185       }
10186       else if (anArgCase == "-fovx")
10187       {
10188         theDI << aCamera->FOVx() << " ";
10189       }
10190       else
10191       {
10192         theDI << aCamera->FOVy() << " ";
10193       }
10194     }
10195     else if (anArgIter + 1 < theArgsNb
10196           && anArgCase == "-xrpose")
10197     {
10198       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
10199       anXRArg.LowerCase();
10200       if (anXRArg == "base")
10201       {
10202         aCamera = aView->View()->BaseXRCamera();
10203       }
10204       else if (anXRArg == "head")
10205       {
10206         aCamera = aView->View()->PosedXRCamera();
10207       }
10208       else
10209       {
10210         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
10211         return 1;
10212       }
10213       if (aCamera.IsNull())
10214       {
10215         Message::SendFail() << "Error: undefined XR pose";
10216         return 0;
10217       }
10218       if (aView->AutoZFitMode())
10219       {
10220         const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (false);
10221         const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (true);
10222         aCamera->ZFitAll (aView->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox);
10223       }
10224     }
10225     else if (aPrsName.IsEmpty()
10226          && !anArgCase.StartsWith ("-"))
10227     {
10228       aPrsName = anArg;
10229     }
10230     else
10231     {
10232       Message::SendFail() << "Error: unknown argument '" << anArg << "'";
10233       return 1;
10234     }
10235   }
10236
10237   if (aPrsName.IsEmpty()
10238    || theArgsNb > 2)
10239   {
10240     aView->Redraw();
10241   }
10242
10243   if (!aPrsName.IsEmpty())
10244   {
10245     Handle(AIS_CameraFrustum) aCameraFrustum;
10246     if (GetMapOfAIS().IsBound2 (aPrsName))
10247     {
10248       // find existing object
10249       aCameraFrustum = Handle(AIS_CameraFrustum)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
10250       if (aCameraFrustum.IsNull())
10251       {
10252         Message::SendFail() << "Error: object '" << aPrsName << "'is already defined and is not a camera frustum";
10253         return 1;
10254       }
10255     }
10256
10257     if (aCameraFrustum.IsNull())
10258     {
10259       aCameraFrustum = new AIS_CameraFrustum();
10260     }
10261     else
10262     {
10263       // not include displayed object of old camera frustum in the new one.
10264       ViewerTest::GetAISContext()->Erase (aCameraFrustum, false);
10265       aView->ZFitAll();
10266     }
10267     aCameraFrustum->SetCameraFrustum (aCamera);
10268
10269     ViewerTest::Display (aPrsName, aCameraFrustum);
10270   }
10271
10272   return 0;
10273 }
10274
10275 //! Parse stereo output mode
10276 inline Standard_Boolean parseStereoMode (Standard_CString      theArg,
10277                                          Graphic3d_StereoMode& theMode)
10278 {
10279   TCollection_AsciiString aFlag (theArg);
10280   aFlag.LowerCase();
10281   if (aFlag == "quadbuffer")
10282   {
10283     theMode = Graphic3d_StereoMode_QuadBuffer;
10284   }
10285   else if (aFlag == "anaglyph")
10286   {
10287     theMode = Graphic3d_StereoMode_Anaglyph;
10288   }
10289   else if (aFlag == "row"
10290         || aFlag == "rowinterlaced")
10291   {
10292     theMode = Graphic3d_StereoMode_RowInterlaced;
10293   }
10294   else if (aFlag == "col"
10295         || aFlag == "colinterlaced"
10296         || aFlag == "columninterlaced")
10297   {
10298     theMode = Graphic3d_StereoMode_ColumnInterlaced;
10299   }
10300   else if (aFlag == "chess"
10301         || aFlag == "chessboard")
10302   {
10303     theMode = Graphic3d_StereoMode_ChessBoard;
10304   }
10305   else if (aFlag == "sbs"
10306         || aFlag == "sidebyside")
10307   {
10308     theMode = Graphic3d_StereoMode_SideBySide;
10309   }
10310   else if (aFlag == "ou"
10311         || aFlag == "overunder")
10312   {
10313     theMode = Graphic3d_StereoMode_OverUnder;
10314   }
10315   else if (aFlag == "pageflip"
10316         || aFlag == "softpageflip")
10317   {
10318     theMode = Graphic3d_StereoMode_SoftPageFlip;
10319   }
10320   else if (aFlag == "openvr"
10321         || aFlag == "vr")
10322   {
10323     theMode = Graphic3d_StereoMode_OpenVR;
10324   }
10325   else
10326   {
10327     return Standard_False;
10328   }
10329   return Standard_True;
10330 }
10331
10332 //! Parse anaglyph filter
10333 inline Standard_Boolean parseAnaglyphFilter (Standard_CString                     theArg,
10334                                              Graphic3d_RenderingParams::Anaglyph& theFilter)
10335 {
10336   TCollection_AsciiString aFlag (theArg);
10337   aFlag.LowerCase();
10338   if (aFlag == "redcyansimple")
10339   {
10340     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10341   }
10342   else if (aFlag == "redcyan"
10343         || aFlag == "redcyanoptimized")
10344   {
10345     theFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized;
10346   }
10347   else if (aFlag == "yellowbluesimple")
10348   {
10349     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple;
10350   }
10351   else if (aFlag == "yellowblue"
10352         || aFlag == "yellowblueoptimized")
10353   {
10354     theFilter = Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized;
10355   }
10356   else if (aFlag == "greenmagenta"
10357         || aFlag == "greenmagentasimple")
10358   {
10359     theFilter = Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple;
10360   }
10361   else
10362   {
10363     return Standard_False;
10364   }
10365   return Standard_True;
10366 }
10367
10368 //==============================================================================
10369 //function : VStereo
10370 //purpose  :
10371 //==============================================================================
10372
10373 static int VStereo (Draw_Interpretor& theDI,
10374                     Standard_Integer  theArgNb,
10375                     const char**      theArgVec)
10376 {
10377   Handle(V3d_View) aView = ViewerTest::CurrentView();
10378   if (theArgNb < 2)
10379   {
10380     if (aView.IsNull())
10381     {
10382       Message::SendFail ("Error: no active viewer");
10383       return 0;
10384     }
10385
10386     Standard_Boolean isActive = ViewerTest_myDefaultCaps.contextStereo;
10387     theDI << "Stereo " << (isActive ? "ON" : "OFF") << "\n";
10388     if (isActive)
10389     {
10390       TCollection_AsciiString aMode;
10391       switch (aView->RenderingParams().StereoMode)
10392       {
10393         case Graphic3d_StereoMode_QuadBuffer       : aMode = "quadBuffer";       break;
10394         case Graphic3d_StereoMode_RowInterlaced    : aMode = "rowInterlaced";    break;
10395         case Graphic3d_StereoMode_ColumnInterlaced : aMode = "columnInterlaced"; break;
10396         case Graphic3d_StereoMode_ChessBoard       : aMode = "chessBoard";       break;
10397         case Graphic3d_StereoMode_SideBySide       : aMode = "sideBySide";       break;
10398         case Graphic3d_StereoMode_OverUnder        : aMode = "overUnder";        break;
10399         case Graphic3d_StereoMode_SoftPageFlip     : aMode = "softpageflip";     break;
10400         case Graphic3d_StereoMode_OpenVR           : aMode = "openVR";           break;
10401         case Graphic3d_StereoMode_Anaglyph  :
10402           aMode = "anaglyph";
10403           switch (aView->RenderingParams().AnaglyphFilter)
10404           {
10405             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple      : aMode.AssignCat (" (redCyanSimple)");      break;
10406             case Graphic3d_RenderingParams::Anaglyph_RedCyan_Optimized   : aMode.AssignCat (" (redCyan)");            break;
10407             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Simple   : aMode.AssignCat (" (yellowBlueSimple)");   break;
10408             case Graphic3d_RenderingParams::Anaglyph_YellowBlue_Optimized: aMode.AssignCat (" (yellowBlue)");         break;
10409             case Graphic3d_RenderingParams::Anaglyph_GreenMagenta_Simple : aMode.AssignCat (" (greenMagentaSimple)"); break;
10410             default: break;
10411           }
10412         default: break;
10413       }
10414       theDI << "Mode " << aMode << "\n";
10415     }
10416     return 0;
10417   }
10418
10419   Handle(Graphic3d_Camera) aCamera;
10420   Graphic3d_RenderingParams*   aParams   = NULL;
10421   Graphic3d_StereoMode         aMode     = Graphic3d_StereoMode_QuadBuffer;
10422   if (!aView.IsNull())
10423   {
10424     aParams   = &aView->ChangeRenderingParams();
10425     aMode     = aParams->StereoMode;
10426     aCamera   = aView->Camera();
10427   }
10428
10429   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10430   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
10431   {
10432     Standard_CString        anArg = theArgVec[anArgIter];
10433     TCollection_AsciiString aFlag (anArg);
10434     aFlag.LowerCase();
10435     if (anUpdateTool.parseRedrawMode (aFlag))
10436     {
10437       continue;
10438     }
10439     else if (aFlag == "0"
10440           || aFlag == "off")
10441     {
10442       if (++anArgIter < theArgNb)
10443       {
10444         Message::SendFail ("Error: wrong number of arguments");
10445         return 1;
10446       }
10447
10448       if (!aCamera.IsNull()
10449        &&  aCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
10450       {
10451         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Perspective);
10452       }
10453       ViewerTest_myDefaultCaps.contextStereo = Standard_False;
10454       return 0;
10455     }
10456     else if (aFlag == "1"
10457           || aFlag == "on")
10458     {
10459       if (++anArgIter < theArgNb)
10460       {
10461         Message::SendFail ("Error: wrong number of arguments");
10462         return 1;
10463       }
10464
10465       if (!aCamera.IsNull())
10466       {
10467         aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10468       }
10469       ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10470       if (aParams->StereoMode != Graphic3d_StereoMode_OpenVR)
10471       {
10472         return 0;
10473       }
10474     }
10475     else if (aFlag == "-reverse"
10476           || aFlag == "-reversed"
10477           || aFlag == "-swap")
10478     {
10479       Standard_Boolean toEnable = Standard_True;
10480       if (++anArgIter < theArgNb
10481       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10482       {
10483         --anArgIter;
10484       }
10485       aParams->ToReverseStereo = toEnable;
10486     }
10487     else if (aFlag == "-noreverse"
10488           || aFlag == "-noswap")
10489     {
10490       Standard_Boolean toDisable = Standard_True;
10491       if (++anArgIter < theArgNb
10492       && !Draw::ParseOnOff (theArgVec[anArgIter], toDisable))
10493       {
10494         --anArgIter;
10495       }
10496       aParams->ToReverseStereo = !toDisable;
10497     }
10498     else if (aFlag == "-mode"
10499           || aFlag == "-stereomode")
10500     {
10501       if (++anArgIter >= theArgNb
10502       || !parseStereoMode (theArgVec[anArgIter], aMode))
10503       {
10504         Message::SendFail() << "Syntax error at '" << anArg << "'";
10505         return 1;
10506       }
10507
10508       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10509       {
10510         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10511       }
10512     }
10513     else if (aFlag == "-anaglyph"
10514           || aFlag == "-anaglyphfilter")
10515     {
10516       Graphic3d_RenderingParams::Anaglyph aFilter = Graphic3d_RenderingParams::Anaglyph_RedCyan_Simple;
10517       if (++anArgIter >= theArgNb
10518       || !parseAnaglyphFilter (theArgVec[anArgIter], aFilter))
10519       {
10520         Message::SendFail() << "Syntax error at '" << anArg << "'";
10521         return 1;
10522       }
10523
10524       aMode = Graphic3d_StereoMode_Anaglyph;
10525       aParams->AnaglyphFilter = aFilter;
10526     }
10527     else if (parseStereoMode (anArg, aMode)) // short syntax
10528     {
10529       if (aMode == Graphic3d_StereoMode_QuadBuffer)
10530       {
10531         ViewerTest_myDefaultCaps.contextStereo = Standard_True;
10532       }
10533     }
10534     else if (anArgIter + 1 < theArgNb
10535           && aFlag == "-hmdfov2d")
10536     {
10537       aParams->HmdFov2d = (float )Draw::Atof (theArgVec[++anArgIter]);
10538       if (aParams->HmdFov2d < 10.0f
10539        || aParams->HmdFov2d > 180.0f)
10540       {
10541         Message::SendFail() << "Error: FOV is out of range";
10542         return 1;
10543       }
10544     }
10545     else if (aFlag == "-mirror"
10546           || aFlag == "-mirrorcomposer")
10547     {
10548       Standard_Boolean toEnable = Standard_True;
10549       if (++anArgIter < theArgNb
10550       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
10551       {
10552         --anArgIter;
10553       }
10554       aParams->ToMirrorComposer = toEnable;
10555     }
10556     else if (anArgIter + 1 < theArgNb
10557           && (aFlag == "-unitfactor"
10558            || aFlag == "-unitscale"))
10559     {
10560       aView->View()->SetUnitFactor (Draw::Atof (theArgVec[++anArgIter]));
10561     }
10562     else
10563     {
10564       Message::SendFail() << "Syntax error at '" << anArg << "'";
10565       return 1;
10566     }
10567   }
10568
10569   if (!aView.IsNull())
10570   {
10571     aParams->StereoMode = aMode;
10572     aCamera->SetProjectionType (Graphic3d_Camera::Projection_Stereo);
10573     if (aParams->StereoMode == Graphic3d_StereoMode_OpenVR)
10574     {
10575       // initiate implicit continuous rendering
10576       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
10577     }
10578   }
10579   return 0;
10580 }
10581
10582 //===============================================================================================
10583 //function : VDefaults
10584 //purpose  :
10585 //===============================================================================================
10586 static int VDefaults (Draw_Interpretor& theDi,
10587                       Standard_Integer  theArgsNb,
10588                       const char**      theArgVec)
10589 {
10590   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
10591   if (aCtx.IsNull())
10592   {
10593     Message::SendFail ("Error: no active viewer");
10594     return 1;
10595   }
10596
10597   Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
10598   if (theArgsNb < 2)
10599   {
10600     if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
10601     {
10602       theDi << "DeflType:           relative\n"
10603             << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
10604     }
10605     else
10606     {
10607       theDi << "DeflType:           absolute\n"
10608             << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
10609     }
10610     theDi << "AngularDeflection:  " << (180.0 * aDefParams->DeviationAngle() / M_PI) << "\n";
10611     theDi << "AutoTriangulation:  " << (aDefParams->IsAutoTriangulation() ? "on" : "off") << "\n";
10612     return 0;
10613   }
10614
10615   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
10616   {
10617     TCollection_AsciiString anArg (theArgVec[anArgIter]);
10618     anArg.UpperCase();
10619     if (anArg == "-ABSDEFL"
10620      || anArg == "-ABSOLUTEDEFLECTION"
10621      || anArg == "-DEFL"
10622      || anArg == "-DEFLECTION")
10623     {
10624       if (++anArgIter >= theArgsNb)
10625       {
10626         Message::SendFail() << "Syntax error at " << anArg;
10627         return 1;
10628       }
10629       aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
10630       aDefParams->SetMaximalChordialDeviation (Draw::Atof (theArgVec[anArgIter]));
10631     }
10632     else if (anArg == "-RELDEFL"
10633           || anArg == "-RELATIVEDEFLECTION"
10634           || anArg == "-DEVCOEFF"
10635           || anArg == "-DEVIATIONCOEFF"
10636           || anArg == "-DEVIATIONCOEFFICIENT")
10637     {
10638       if (++anArgIter >= theArgsNb)
10639       {
10640         Message::SendFail() << "Syntax error at " << anArg;
10641         return 1;
10642       }
10643       aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
10644       aDefParams->SetDeviationCoefficient (Draw::Atof (theArgVec[anArgIter]));
10645     }
10646     else if (anArg == "-ANGDEFL"
10647           || anArg == "-ANGULARDEFL"
10648           || anArg == "-ANGULARDEFLECTION")
10649     {
10650       if (++anArgIter >= theArgsNb)
10651       {
10652         Message::SendFail() << "Syntax error at " << anArg;
10653         return 1;
10654       }
10655       aDefParams->SetDeviationAngle (M_PI * Draw::Atof (theArgVec[anArgIter]) / 180.0);
10656     }
10657     else if (anArg == "-AUTOTR"
10658           || anArg == "-AUTOTRIANG"
10659           || anArg == "-AUTOTRIANGULATION")
10660     {
10661       ++anArgIter;
10662       bool toTurnOn = true;
10663       if (anArgIter >= theArgsNb
10664       || !Draw::ParseOnOff (theArgVec[anArgIter], toTurnOn))
10665       {
10666         Message::SendFail() << "Syntax error at '" << anArg << "'";
10667         return 1;
10668       }
10669       aDefParams->SetAutoTriangulation (toTurnOn);
10670     }
10671     else
10672     {
10673       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
10674       return 1;
10675     }
10676   }
10677
10678   return 0;
10679 }
10680
10681 //! Auxiliary method
10682 inline void addLight (const Handle(V3d_Light)& theLightNew,
10683                       const Graphic3d_ZLayerId theLayer,
10684                       const Standard_Boolean   theIsGlobal)
10685 {
10686   if (theLightNew.IsNull())
10687   {
10688     return;
10689   }
10690
10691   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10692   if (theLayer == Graphic3d_ZLayerId_UNKNOWN)
10693   {
10694     aViewer->AddLight (theLightNew);
10695     if (theIsGlobal)
10696     {
10697       aViewer->SetLightOn (theLightNew);
10698     }
10699     else
10700     {
10701       ViewerTest::CurrentView()->SetLightOn (theLightNew);
10702     }
10703   }
10704   else
10705   {
10706     Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (theLayer);
10707     if (aSettings.Lights().IsNull())
10708     {
10709       aSettings.SetLights (new Graphic3d_LightSet());
10710     }
10711     aSettings.Lights()->Add (theLightNew);
10712     aViewer->SetZLayerSettings (theLayer, aSettings);
10713   }
10714 }
10715
10716 //! Auxiliary method
10717 inline Standard_Integer getLightId (const TCollection_AsciiString& theArgNext)
10718 {
10719   TCollection_AsciiString anArgNextCase (theArgNext);
10720   anArgNextCase.UpperCase();
10721   if (anArgNextCase.Length() > 5
10722    && anArgNextCase.SubString (1, 5).IsEqual ("LIGHT"))
10723   {
10724     return theArgNext.SubString (6, theArgNext.Length()).IntegerValue();
10725   }
10726   else
10727   {
10728     return theArgNext.IntegerValue();
10729   }
10730 }
10731
10732 static Handle(AIS_LightSource) findLightPrs (const Handle(V3d_Light)& theLight,
10733                                              const bool theToShowErrors = true)
10734 {
10735   if (theLight.IsNull())
10736   {
10737     if (theToShowErrors)
10738     {
10739       Message::SendFail() << "Syntax error: no active light source to find presentation";
10740     }
10741     return Handle(AIS_LightSource)();
10742   }
10743
10744   Handle(AIS_InteractiveObject) anObject;
10745   GetMapOfAIS().Find2 (theLight->Name(), anObject);
10746   Handle(AIS_LightSource) aLightSource = Handle(AIS_LightSource)::DownCast (anObject);
10747   if (aLightSource.IsNull())
10748   {
10749     if (theToShowErrors)
10750     {
10751       Message::SendFail() << "Syntax error: could not find '" << theLight->Name() << "' AIS object";
10752     }
10753   }
10754   return aLightSource;
10755 }
10756
10757 //===============================================================================================
10758 //function : VLight
10759 //purpose  :
10760 //===============================================================================================
10761 static int VLight (Draw_Interpretor& theDi,
10762                    Standard_Integer  theArgsNb,
10763                    const char**      theArgVec)
10764 {
10765   Handle(V3d_View)   aView   = ViewerTest::CurrentView();
10766   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
10767   if (aView.IsNull()
10768    || aViewer.IsNull())
10769   {
10770     Message::SendFail ("Error: no active viewer");
10771     return 1;
10772   }
10773
10774   Standard_Real anXYZ[3]   = {};
10775   Standard_Real anAtten[2] = {};
10776   if (theArgsNb < 2)
10777   {
10778     // print lights info
10779     Standard_Integer aLightId = 0;
10780     for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightId)
10781     {
10782       Handle(V3d_Light) aLight = aLightIter.Value();
10783       const Quantity_Color aColor = aLight->Color();
10784       theDi << "Light #" << aLightId
10785             << (!aLight->Name().IsEmpty() ? (TCollection_AsciiString(" ") + aLight->Name()) : "")
10786             << " [" << aLight->GetId() << "]" << "\n";
10787       switch (aLight->Type())
10788       {
10789         case V3d_AMBIENT:
10790         {
10791           theDi << "  Type:       Ambient\n";
10792           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10793           break;
10794         }
10795         case V3d_DIRECTIONAL:
10796         {
10797           theDi << "  Type:       Directional\n";
10798           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10799           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10800           theDi << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
10801           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10802           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10803           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10804           break;
10805         }
10806         case V3d_POSITIONAL:
10807         {
10808           theDi << "  Type:       Positional\n";
10809           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10810           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10811           theDi << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
10812           theDi << "  Smoothness: " << aLight->Smoothness() << "\n";
10813           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10814           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10815           aLight->Attenuation (anAtten[0], anAtten[1]);
10816           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10817           theDi << "  Range:      " << aLight->Range() << "\n";
10818           break;
10819         }
10820         case V3d_SPOT:
10821         {
10822           theDi << "  Type:       Spot\n";
10823           theDi << "  Intensity:  " << aLight->Intensity() << "\n";
10824           theDi << "  Headlight:  " << (aLight->Headlight() ? "TRUE" : "FALSE") << "\n";
10825           theDi << "  CastShadows:" << (aLight->ToCastShadows() ? "TRUE" : "FALSE") << "\n";
10826           aLight->Position  (anXYZ[0], anXYZ[1], anXYZ[2]);
10827           theDi << "  Position:   " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10828           aLight->Direction (anXYZ[0], anXYZ[1], anXYZ[2]);
10829           theDi << "  Direction:  " << anXYZ[0] << ", " << anXYZ[1] << ", " << anXYZ[2] << "\n";
10830           aLight->Attenuation (anAtten[0], anAtten[1]);
10831           theDi << "  Atten.:     " << anAtten[0] << " " << anAtten[1] << "\n";
10832           theDi << "  Angle:      " << (aLight->Angle() * 180.0 / M_PI) << "\n";
10833           theDi << "  Exponent:   " << aLight->Concentration() << "\n";
10834           theDi << "  Range:      " << aLight->Range() << "\n";
10835           break;
10836         }
10837         default:
10838         {
10839           theDi << "  Type:       UNKNOWN\n";
10840           break;
10841         }
10842       }
10843       theDi << "  Color:      " << aColor.Red() << ", " << aColor.Green() << ", " << aColor.Blue() << " [" << Quantity_Color::StringName (aColor.Name()) << "]\n";
10844     }
10845   }
10846
10847   Handle(V3d_Light) aLightNew, aLightOld;
10848   Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN;
10849   Standard_Boolean  isGlobal = Standard_True;
10850   Standard_Boolean  toCreate = Standard_False;
10851   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
10852   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
10853   {
10854     Handle(V3d_Light) aLightCurr = aLightNew.IsNull() ? aLightOld : aLightNew;
10855
10856     TCollection_AsciiString aName, aValue;
10857     const TCollection_AsciiString anArg (theArgVec[anArgIt]);
10858     TCollection_AsciiString anArgCase (anArg);
10859     anArgCase.UpperCase();
10860     if (anUpdateTool.parseRedrawMode (anArg))
10861     {
10862       continue;
10863     }
10864
10865     if (anArgCase.IsEqual ("NEW")
10866      || anArgCase.IsEqual ("ADD")
10867      || anArgCase.IsEqual ("CREATE")
10868      || anArgCase.IsEqual ("-NEW")
10869      || anArgCase.IsEqual ("-ADD")
10870      || anArgCase.IsEqual ("-CREATE"))
10871     {
10872       toCreate = Standard_True;
10873     }
10874     else if (anArgCase.IsEqual ("-LAYER")
10875           || anArgCase.IsEqual ("-ZLAYER"))
10876     {
10877       if (++anArgIt >= theArgsNb)
10878       {
10879         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10880         return 1;
10881       }
10882
10883       TCollection_AsciiString aValStr (theArgVec[anArgIt]);
10884       aValStr.LowerCase();
10885       if (aValStr == "default"
10886        || aValStr == "def")
10887       {
10888         aLayer = Graphic3d_ZLayerId_Default;
10889       }
10890       else if (aValStr == "top")
10891       {
10892         aLayer = Graphic3d_ZLayerId_Top;
10893       }
10894       else if (aValStr == "topmost")
10895       {
10896         aLayer = Graphic3d_ZLayerId_Topmost;
10897       }
10898       else if (aValStr == "toposd"
10899             || aValStr == "osd")
10900       {
10901         aLayer = Graphic3d_ZLayerId_TopOSD;
10902       }
10903       else if (aValStr == "botosd"
10904             || aValStr == "bottom")
10905       {
10906         aLayer = Graphic3d_ZLayerId_BotOSD;
10907       }
10908       else if (aValStr.IsIntegerValue())
10909       {
10910         aLayer = Draw::Atoi (theArgVec[anArgIt]);
10911       }
10912       else
10913       {
10914         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10915         return 1;
10916       }
10917     }
10918     else if (anArgCase.IsEqual ("GLOB")
10919           || anArgCase.IsEqual ("GLOBAL")
10920           || anArgCase.IsEqual ("-GLOB")
10921           || anArgCase.IsEqual ("-GLOBAL"))
10922     {
10923       isGlobal = Standard_True;
10924     }
10925     else if (anArgCase.IsEqual ("LOC")
10926           || anArgCase.IsEqual ("LOCAL")
10927           || anArgCase.IsEqual ("-LOC")
10928           || anArgCase.IsEqual ("-LOCAL"))
10929     {
10930       isGlobal = Standard_False;
10931     }
10932     else if (anArgCase.IsEqual ("DEF")
10933           || anArgCase.IsEqual ("DEFAULTS")
10934           || anArgCase.IsEqual ("-DEF")
10935           || anArgCase.IsEqual ("-DEFAULTS"))
10936     {
10937       toCreate = Standard_False;
10938       aViewer->SetDefaultLights();
10939     }
10940     else if (anArgCase.IsEqual ("CLR")
10941           || anArgCase.IsEqual ("CLEAR")
10942           || anArgCase.IsEqual ("-CLR")
10943           || anArgCase.IsEqual ("-CLEAR"))
10944     {
10945       toCreate = Standard_False;
10946
10947       TColStd_SequenceOfInteger aLayers;
10948       aViewer->GetAllZLayers (aLayers);
10949       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
10950       {
10951         if (aLayeriter.Value() == aLayer
10952          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
10953         {
10954           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
10955           aSettings.SetLights (Handle(Graphic3d_LightSet)());
10956           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
10957           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
10958           {
10959             break;
10960           }
10961         }
10962       }
10963
10964       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
10965       {
10966         ViewerTest_DoubleMapOfInteractiveAndName aMap = GetMapOfAIS();
10967         for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();)
10968         {
10969           Handle(V3d_Light) aLight = aLightIter.Value();
10970           if (Handle(AIS_LightSource) aLightSourceDel = findLightPrs (aLight, false))
10971           {
10972             ViewerTest::GetAISContext()->Remove (aLightSourceDel, false);
10973             GetMapOfAIS().UnBind2 (aLight->Name());
10974           }
10975           aViewer->DelLight (aLight);
10976           aLightIter = aView->ActiveLightIterator();
10977         }
10978       }
10979     }
10980     else if (anArgCase.IsEqual ("AMB")
10981           || anArgCase.IsEqual ("AMBIENT")
10982           || anArgCase.IsEqual ("AMBLIGHT"))
10983     {
10984       if (!toCreate)
10985       {
10986         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
10987         return 1;
10988       }
10989
10990       addLight (aLightNew, aLayer, isGlobal);
10991       toCreate  = Standard_False;
10992       aLightNew = new V3d_AmbientLight();
10993     }
10994     else if (anArgCase.IsEqual ("DIRECTIONAL")
10995           || anArgCase.IsEqual ("DIRLIGHT"))
10996     {
10997       if (!toCreate)
10998       {
10999         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11000         return 1;
11001       }
11002
11003       addLight (aLightNew, aLayer, isGlobal);
11004       toCreate  = Standard_False;
11005       aLightNew = new V3d_DirectionalLight();
11006     }
11007     else if (anArgCase.IsEqual ("SPOT")
11008           || anArgCase.IsEqual ("SPOTLIGHT"))
11009     {
11010       if (!toCreate)
11011       {
11012         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11013         return 1;
11014       }
11015
11016       addLight (aLightNew, aLayer, isGlobal);
11017       toCreate  = Standard_False;
11018       aLightNew = new V3d_SpotLight (gp_Pnt (0.0, 0.0, 0.0));
11019     }
11020     else if (anArgCase.IsEqual ("POSLIGHT")
11021           || anArgCase.IsEqual ("POSITIONAL"))
11022     {
11023       if (!toCreate)
11024       {
11025         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11026         return 1;
11027       }
11028
11029       addLight (aLightNew, aLayer, isGlobal);
11030       toCreate  = Standard_False;
11031       aLightNew = new V3d_PositionalLight (gp_Pnt (0.0, 0.0, 0.0));
11032     }
11033     else if (anArgCase.IsEqual ("CHANGE")
11034           || anArgCase.IsEqual ("-CHANGE"))
11035     {
11036       if (++anArgIt >= theArgsNb)
11037       {
11038         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11039         return 1;
11040       }
11041
11042       addLight (aLightNew, aLayer, isGlobal);
11043       aLightNew.Nullify();
11044       const Standard_Integer aLightId = getLightId (theArgVec[anArgIt]);
11045       Standard_Integer aLightIt = 0;
11046       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
11047       {
11048         if (aLightIt == aLightId)
11049         {
11050           aLightOld = aLightIter.Value();
11051           break;
11052         }
11053       }
11054
11055       if (aLightOld.IsNull())
11056       {
11057         Message::SendFail() << "Error: Light " << theArgVec[anArgIt] << " is undefined";
11058         return 1;
11059       }
11060     }
11061     else if (anArgCase == "-DISPLAY"
11062           || anArgCase == "-DISP"
11063           || anArgCase == "-PRESENTATION"
11064           || anArgCase == "-PRS")
11065     {
11066       if (aLightCurr.IsNull())
11067       {
11068         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11069         return 1;
11070       }
11071
11072       TCollection_AsciiString aLightName = aLightCurr->Name();
11073       if (++anArgIt > theArgsNb
11074        && aLightName.IsEmpty())
11075       {
11076         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11077         return 1;
11078       }
11079       if (anArgIt < theArgsNb)
11080       {
11081         if (theArgVec[anArgIt][0] != '-')
11082         {
11083           aLightName = theArgVec[anArgIt];
11084           aLightCurr->SetName (aLightName);
11085         }
11086         else
11087         {
11088           --anArgIt;
11089         }
11090       }
11091       if (aLightName.IsEmpty())
11092       {
11093         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11094         return 1;
11095       }
11096       ViewerTest::Display (aLightName, new AIS_LightSource (aLightCurr), false);
11097     }
11098     else if (anArgCase == "DEL"
11099           || anArgCase == "DELETE"
11100           || anArgCase == "-DEL"
11101           || anArgCase == "-DELETE"
11102           || anArgCase == "-REMOVE")
11103     {
11104       Handle(V3d_Light) aLightDel;
11105       if (++anArgIt >= theArgsNb)
11106       {
11107         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11108         return 1;
11109       }
11110
11111       const TCollection_AsciiString anArgNext (theArgVec[anArgIt]);
11112       const Standard_Integer aLightDelId = getLightId (theArgVec[anArgIt]);
11113       Standard_Integer aLightIt = 0;
11114       for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More(); aLightIter.Next(), ++aLightIt)
11115       {
11116         aLightDel = aLightIter.Value();
11117         if (aLightIt == aLightDelId)
11118         {
11119           break;
11120         }
11121       }
11122       if (aLightDel.IsNull())
11123       {
11124         continue;
11125       }
11126
11127       TColStd_SequenceOfInteger aLayers;
11128       aViewer->GetAllZLayers (aLayers);
11129       for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
11130       {
11131         if (aLayeriter.Value() == aLayer
11132          || aLayer == Graphic3d_ZLayerId_UNKNOWN)
11133         {
11134           Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
11135           if (!aSettings.Lights().IsNull())
11136           {
11137             aSettings.Lights()->Remove (aLightDel);
11138             if (aSettings.Lights()->IsEmpty())
11139             {
11140               aSettings.SetLights (Handle(Graphic3d_LightSet)());
11141             }
11142           }
11143           aViewer->SetZLayerSettings (aLayeriter.Value(), aSettings);
11144           if (aLayer != Graphic3d_ZLayerId_UNKNOWN)
11145           {
11146             break;
11147           }
11148         }
11149       }
11150
11151       if (aLayer == Graphic3d_ZLayerId_UNKNOWN)
11152       {
11153         if (Handle(AIS_LightSource) aLightSourceDel = findLightPrs (aLightDel, false))
11154         {
11155           ViewerTest::GetAISContext()->Remove (aLightSourceDel, false);
11156           GetMapOfAIS().UnBind2 (aLightDel->Name());
11157         }
11158         aViewer->DelLight (aLightDel);
11159       }
11160     }
11161     else if (anArgCase.IsEqual ("COLOR")
11162           || anArgCase.IsEqual ("COLOUR")
11163           || anArgCase.IsEqual ("-COLOR")
11164           || anArgCase.IsEqual ("-COLOUR"))
11165     {
11166       Quantity_Color aColor;
11167       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIt - 1,
11168                                                      theArgVec + anArgIt + 1,
11169                                                      aColor);
11170       anArgIt += aNbParsed;
11171       if (aNbParsed == 0
11172        || aLightCurr.IsNull())
11173       {
11174         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11175         return 1;
11176       }
11177       aLightCurr->SetColor (aColor);
11178     }
11179     else if (anArgCase == "POS"
11180           || anArgCase == "POSITION"
11181           || anArgCase == "-POS"
11182           || anArgCase == "-POSITION"
11183           || anArgCase == "-PRSPOSITION"
11184           || anArgCase == "-PRSPOS")
11185     {
11186       gp_XYZ aPosXYZ;
11187       if ((anArgIt + 3) >= theArgsNb
11188        || !parseXYZ (theArgVec + anArgIt + 1, aPosXYZ)
11189        || aLightCurr.IsNull())
11190       {
11191         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11192         return 1;
11193       }
11194
11195       anArgIt += 3;
11196       if (anArgCase == "-PRSPOSITION"
11197        || anArgCase == "-PRSPOS")
11198       {
11199         aLightCurr->SetDisplayPosition (aPosXYZ);
11200       }
11201       else
11202       {
11203         if (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11204          && aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11205         {
11206           Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11207           return 1;
11208         }
11209
11210         aLightCurr->SetPosition (aPosXYZ);
11211       }
11212     }
11213     else if (anArgCase.IsEqual ("DIR")
11214           || anArgCase.IsEqual ("DIRECTION")
11215           || anArgCase.IsEqual ("-DIR")
11216           || anArgCase.IsEqual ("-DIRECTION"))
11217     {
11218       gp_XYZ aDirXYZ;
11219       if ((anArgIt + 3) >= theArgsNb
11220        || !parseXYZ (theArgVec + anArgIt + 1, aDirXYZ)
11221        || aLightCurr.IsNull()
11222        || (aLightCurr->Type() != Graphic3d_TOLS_DIRECTIONAL
11223         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11224       {
11225         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11226         return 1;
11227       }
11228
11229       anArgIt += 3;
11230       aLightCurr->SetDirection (gp_Dir (aDirXYZ));
11231     }
11232     else if (anArgCase.IsEqual ("SM")
11233           || anArgCase.IsEqual ("SMOOTHNESS")
11234           || anArgCase.IsEqual ("-SM")
11235           || anArgCase.IsEqual ("-SMOOTHNESS"))
11236     {
11237       if (++anArgIt >= theArgsNb
11238        || aLightCurr.IsNull())
11239       {
11240         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11241         return 1;
11242       }
11243
11244       Standard_ShortReal aSmoothness = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11245       if (Abs (aSmoothness) <= ShortRealEpsilon())
11246       {
11247         aLightCurr->SetIntensity (1.f);
11248       }
11249       else if (Abs (aLightCurr->Smoothness()) <= ShortRealEpsilon())
11250       {
11251         aLightCurr->SetIntensity ((aSmoothness * aSmoothness) / 3.f);
11252       }
11253       else
11254       {
11255         Standard_ShortReal aSmoothnessRatio = static_cast<Standard_ShortReal> (aSmoothness / aLightCurr->Smoothness());
11256         aLightCurr->SetIntensity (aLightCurr->Intensity() / (aSmoothnessRatio * aSmoothnessRatio));
11257       }
11258
11259       if (aLightCurr->Type() == Graphic3d_TOLS_POSITIONAL)
11260       {
11261         aLightCurr->SetSmoothRadius (aSmoothness);
11262       }
11263       else if (aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11264       {
11265         aLightCurr->SetSmoothAngle (aSmoothness);
11266       }
11267     }
11268     else if (anArgCase.IsEqual ("INT")
11269           || anArgCase.IsEqual ("INTENSITY")
11270           || anArgCase.IsEqual ("-INT")
11271           || anArgCase.IsEqual ("-INTENSITY"))
11272     {
11273       if (++anArgIt >= theArgsNb
11274        || aLightCurr.IsNull())
11275       {
11276         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11277         return 1;
11278       }
11279
11280       Standard_ShortReal aIntensity = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11281       aLightCurr->SetIntensity (aIntensity);
11282     }
11283     else if (anArgCase.IsEqual ("ANG")
11284           || anArgCase.IsEqual ("ANGLE")
11285           || anArgCase.IsEqual ("-ANG")
11286           || anArgCase.IsEqual ("-ANGLE"))
11287     {
11288       if (++anArgIt >= theArgsNb
11289        || aLightCurr.IsNull()
11290        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11291       {
11292         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11293         return 1;
11294       }
11295       Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[anArgIt]);
11296       anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI));
11297       aLightCurr->SetAngle (anAngle);
11298     }
11299     else if (anArgCase.IsEqual ("CONSTATTEN")
11300           || anArgCase.IsEqual ("CONSTATTENUATION")
11301           || anArgCase.IsEqual ("-CONSTATTEN")
11302           || anArgCase.IsEqual ("-CONSTATTENUATION"))
11303     {
11304       if (++anArgIt >= theArgsNb
11305        || aLightCurr.IsNull()
11306        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11307         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11308       {
11309         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11310         return 1;
11311       }
11312
11313       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11314       anAtten[0] = Atof (theArgVec[anArgIt]);
11315       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11316     }
11317     else if (anArgCase.IsEqual ("LINATTEN")
11318           || anArgCase.IsEqual ("LINEARATTEN")
11319           || anArgCase.IsEqual ("LINEARATTENUATION")
11320           || anArgCase.IsEqual ("-LINATTEN")
11321           || anArgCase.IsEqual ("-LINEARATTEN")
11322           || anArgCase.IsEqual ("-LINEARATTENUATION"))
11323     {
11324       if (++anArgIt >= theArgsNb
11325        || aLightCurr.IsNull()
11326        || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL
11327         && aLightCurr->Type() != Graphic3d_TOLS_SPOT))
11328       {
11329         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11330         return 1;
11331       }
11332
11333       aLightCurr->Attenuation (anAtten[0], anAtten[1]);
11334       anAtten[1] = Atof (theArgVec[anArgIt]);
11335       aLightCurr->SetAttenuation ((Standard_ShortReal )anAtten[0], (Standard_ShortReal )anAtten[1]);
11336     }
11337     else if (anArgCase.IsEqual ("EXP")
11338           || anArgCase.IsEqual ("EXPONENT")
11339           || anArgCase.IsEqual ("SPOTEXP")
11340           || anArgCase.IsEqual ("SPOTEXPONENT")
11341           || anArgCase.IsEqual ("-EXP")
11342           || anArgCase.IsEqual ("-EXPONENT")
11343           || anArgCase.IsEqual ("-SPOTEXP")
11344           || anArgCase.IsEqual ("-SPOTEXPONENT"))
11345     {
11346       if (++anArgIt >= theArgsNb
11347        || aLightCurr.IsNull()
11348        || aLightCurr->Type() != Graphic3d_TOLS_SPOT)
11349       {
11350         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11351         return 1;
11352       }
11353
11354       aLightCurr->SetConcentration ((Standard_ShortReal )Atof (theArgVec[anArgIt]));
11355     }
11356     else if (anArgCase.IsEqual("RANGE")
11357           || anArgCase.IsEqual("-RANGE"))
11358     {
11359       if (++anArgIt >= theArgsNb
11360        || aLightCurr.IsNull()
11361        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT
11362        || aLightCurr->Type() == Graphic3d_TOLS_DIRECTIONAL)
11363       {
11364         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11365         return 1;
11366       }
11367       Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[anArgIt]));
11368       aLightCurr->SetRange (aRange);
11369     }
11370     else if (anArgCase.IsEqual ("HEAD")
11371           || anArgCase.IsEqual ("HEADLIGHT")
11372           || anArgCase.IsEqual ("-HEAD")
11373           || anArgCase.IsEqual ("-HEADLIGHT"))
11374     {
11375       if (aLightCurr.IsNull()
11376        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT)
11377       {
11378         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11379         return 1;
11380       }
11381
11382       Standard_Boolean isHeadLight = Standard_True;
11383       if (anArgIt + 1 < theArgsNb
11384        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isHeadLight))
11385       {
11386         ++anArgIt;
11387       }
11388       aLightCurr->SetHeadlight (isHeadLight);
11389     }
11390     else if (anArgCase.IsEqual ("NAME")
11391           || anArgCase.IsEqual ("-NAME"))
11392     {
11393       if ((anArgIt + 1) >= theArgsNb
11394         || aLightCurr.IsNull())
11395       {
11396         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11397         return 1;
11398       }
11399       aName = theArgVec[++anArgIt];
11400       aLightCurr->SetName (aName);
11401     }
11402     else if (anArgCase == "-SHOWZOOMABLE"
11403           || anArgCase == "-PRSZOOMABLE"
11404           || anArgCase == "-ZOOMABLE")
11405     {
11406       if (aLightCurr.IsNull())
11407       {
11408         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11409         return 1;
11410       }
11411
11412       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11413       {
11414         const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
11415         aLightSource->SetZoomable (isZoomable);
11416       }
11417       else
11418       {
11419         return 1;
11420       }
11421     }
11422     else if (anArgCase == "-SHOWNAME"
11423           || anArgCase == "-PRSNAME")
11424     {
11425       if (aLightCurr.IsNull())
11426       {
11427         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11428         return 1;
11429       }
11430
11431       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11432       {
11433         const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
11434         aLightSource->SetDisplayName (toDisplay);
11435       }
11436       else
11437       {
11438         return 1;
11439       }
11440     }
11441     else if (anArgCase == "-SHOWRANGE"
11442           || anArgCase == "-PRSRANGE")
11443     {
11444       if (aLightCurr.IsNull()
11445       || (aLightCurr->Type() != Graphic3d_TOLS_SPOT
11446        && aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL))
11447       {
11448         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11449         return 1;
11450       }
11451
11452       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11453       {
11454         const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt);
11455         aLightSource->SetDisplayRange (toDisplay);
11456       }
11457       else
11458       {
11459         return 1;
11460       }
11461     }
11462     else if (anArgCase == "-SHOWSIZE"
11463           || anArgCase == "-PRSSIZE")
11464     {
11465       Standard_Real aSize = 0.0;
11466       if ((anArgIt + 1) >= theArgsNb
11467       || !Draw::ParseReal (theArgVec[anArgIt + 1], aSize)
11468       ||  aSize <= 0.0)
11469       {
11470         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11471         return 1;
11472       }
11473
11474       ++anArgIt;
11475       if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr))
11476       {
11477         aLightSource->SetSize (aSize);
11478       }
11479       else
11480       {
11481         return 1;
11482       }
11483     }
11484     else if (anArgCase.IsEqual ("-CASTSHADOW")
11485           || anArgCase.IsEqual ("-CASTSHADOWS")
11486           || anArgCase.IsEqual ("-SHADOWS"))
11487     {
11488       if (aLightCurr.IsNull()
11489        || aLightCurr->Type() == Graphic3d_TOLS_AMBIENT)
11490       {
11491         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11492         return 1;
11493       }
11494
11495       bool toCastShadows = true;
11496       if (anArgIt + 1 < theArgsNb
11497        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toCastShadows))
11498       {
11499         ++anArgIt;
11500       }
11501       aLightCurr->SetCastShadows (toCastShadows);
11502     }
11503     else
11504     {
11505       Message::SendFail() << "Warning: unknown argument '" << anArg << "'";
11506     }
11507   }
11508
11509   addLight (aLightNew, aLayer, isGlobal);
11510
11511   struct LightPrsSort
11512   {
11513     bool operator() (const Handle(AIS_LightSource)& theLeft,
11514                      const Handle(AIS_LightSource)& theRight)
11515     {
11516       return theLeft->Light()->GetId() < theRight->Light()->GetId();
11517     }
11518   };
11519
11520   AIS_ListOfInteractive aPrsList;
11521   ViewerTest::GetAISContext()->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList);
11522   if (!aPrsList.IsEmpty())
11523   {
11524     // update light source presentations
11525     std::vector<Handle(AIS_LightSource)> aLightPrsVec;
11526     for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next())
11527     {
11528       if (Handle(AIS_LightSource) aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsIter.Value()))
11529       {
11530         aLightPrsVec.push_back (aLightPrs);
11531       }
11532     }
11533
11534     // sort objects by id as AIS_InteractiveContext stores them in unordered map
11535     std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort());
11536
11537     Standard_Integer aTopStack = 0;
11538     for (std::vector<Handle(AIS_LightSource)>::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter)
11539     {
11540       Handle(AIS_LightSource) aLightPrs = *aPrsIter;
11541       if (!aLightPrs->TransformPersistence().IsNull()
11542         && aLightPrs->TransformPersistence()->IsTrihedronOr2d())
11543       {
11544         const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs->Size();
11545         aLightPrs->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize));
11546         aTopStack += aPrsSize + aPrsSize / 2;
11547       }
11548       ViewerTest::GetAISContext()->Redisplay (aLightPrs, false);
11549       ViewerTest::GetAISContext()->SetTransformPersistence (aLightPrs, aLightPrs->TransformPersistence());
11550     }
11551   }
11552   return 0;
11553 }
11554
11555 //===============================================================================================
11556 //function : VPBREnvironment
11557 //purpose  :
11558 //===============================================================================================
11559 static int VPBREnvironment (Draw_Interpretor&,
11560                             Standard_Integer theArgsNb,
11561                             const char**     theArgVec)
11562 {
11563   if (theArgsNb > 2)
11564   {
11565     Message::SendFail ("Syntax error: 'vpbrenv' command has only one argument");
11566     return 1;
11567   }
11568
11569   Handle(V3d_View) aView = ViewerTest::CurrentView();
11570   if (aView.IsNull())
11571   {
11572     Message::SendFail ("Error: no active viewer");
11573     return 1;
11574   }
11575
11576   TCollection_AsciiString anArg = TCollection_AsciiString (theArgVec[1]);
11577   anArg.LowerCase();
11578
11579   if (anArg == "-generate"
11580    || anArg == "-gen")
11581   {
11582     aView->GeneratePBREnvironment (Standard_True);
11583   }
11584   else if (anArg == "-clear")
11585   {
11586     aView->ClearPBREnvironment (Standard_True);
11587   }
11588   else
11589   {
11590     Message::SendFail() << "Syntax error: unknown argument [" << theArgVec[1] << "] for 'vpbrenv' command";
11591     return 1;
11592   }
11593
11594   return 0;
11595 }
11596
11597 //! Read Graphic3d_RenderingParams::PerfCounters flag.
11598 static Standard_Boolean parsePerfStatsFlag (const TCollection_AsciiString& theValue,
11599                                             Standard_Boolean& theToReset,
11600                                             Graphic3d_RenderingParams::PerfCounters& theFlagsRem,
11601                                             Graphic3d_RenderingParams::PerfCounters& theFlagsAdd)
11602 {
11603   Graphic3d_RenderingParams::PerfCounters aFlag = Graphic3d_RenderingParams::PerfCounters_NONE;
11604   TCollection_AsciiString aVal = theValue;
11605   Standard_Boolean toReverse = Standard_False;
11606   if (aVal == "none")
11607   {
11608     theToReset = Standard_True;
11609     return Standard_True;
11610   }
11611   else if (aVal.StartsWith ("-"))
11612   {
11613     toReverse = Standard_True;
11614     aVal = aVal.SubString (2, aVal.Length());
11615   }
11616   else if (aVal.StartsWith ("no"))
11617   {
11618     toReverse = Standard_True;
11619     aVal = aVal.SubString (3, aVal.Length());
11620   }
11621   else if (aVal.StartsWith ("+"))
11622   {
11623     aVal = aVal.SubString (2, aVal.Length());
11624   }
11625   else
11626   {
11627     theToReset = Standard_True;
11628   }
11629
11630   if (     aVal == "fps"
11631         || aVal == "framerate")  aFlag = Graphic3d_RenderingParams::PerfCounters_FrameRate;
11632   else if (aVal == "cpu")        aFlag = Graphic3d_RenderingParams::PerfCounters_CPU;
11633   else if (aVal == "layers")     aFlag = Graphic3d_RenderingParams::PerfCounters_Layers;
11634   else if (aVal == "structs"
11635         || aVal == "structures"
11636         || aVal == "objects")    aFlag = Graphic3d_RenderingParams::PerfCounters_Structures;
11637   else if (aVal == "groups")     aFlag = Graphic3d_RenderingParams::PerfCounters_Groups;
11638   else if (aVal == "arrays")     aFlag = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
11639   else if (aVal == "tris"
11640         || aVal == "triangles")  aFlag = Graphic3d_RenderingParams::PerfCounters_Triangles;
11641   else if (aVal == "pnts"
11642         || aVal == "points")     aFlag = Graphic3d_RenderingParams::PerfCounters_Points;
11643   else if (aVal == "lines")      aFlag = Graphic3d_RenderingParams::PerfCounters_Lines;
11644   else if (aVal == "mem"
11645         || aVal == "gpumem"
11646         || aVal == "estimmem")   aFlag = Graphic3d_RenderingParams::PerfCounters_EstimMem;
11647   else if (aVal == "skipimmediate"
11648         || aVal == "noimmediate") aFlag = Graphic3d_RenderingParams::PerfCounters_SkipImmediate;
11649   else if (aVal == "frametime"
11650         || aVal == "frametimers"
11651         || aVal == "time")       aFlag = Graphic3d_RenderingParams::PerfCounters_FrameTime;
11652   else if (aVal == "basic")      aFlag = Graphic3d_RenderingParams::PerfCounters_Basic;
11653   else if (aVal == "extended"
11654         || aVal == "verbose"
11655         || aVal == "extra")      aFlag = Graphic3d_RenderingParams::PerfCounters_Extended;
11656   else if (aVal == "full"
11657         || aVal == "all")        aFlag = Graphic3d_RenderingParams::PerfCounters_All;
11658   else
11659   {
11660     return Standard_False;
11661   }
11662
11663   if (toReverse)
11664   {
11665     theFlagsRem = Graphic3d_RenderingParams::PerfCounters(theFlagsRem | aFlag);
11666   }
11667   else
11668   {
11669     theFlagsAdd = Graphic3d_RenderingParams::PerfCounters(theFlagsAdd | aFlag);
11670   }
11671   return Standard_True;
11672 }
11673
11674 //! Read Graphic3d_RenderingParams::PerfCounters flags.
11675 static Standard_Boolean convertToPerfStatsFlags (const TCollection_AsciiString& theValue,
11676                                                  Graphic3d_RenderingParams::PerfCounters& theFlags)
11677 {
11678   TCollection_AsciiString aValue = theValue;
11679   Graphic3d_RenderingParams::PerfCounters aFlagsRem = Graphic3d_RenderingParams::PerfCounters_NONE;
11680   Graphic3d_RenderingParams::PerfCounters aFlagsAdd = Graphic3d_RenderingParams::PerfCounters_NONE;
11681   Standard_Boolean toReset = Standard_False;
11682   for (;;)
11683   {
11684     Standard_Integer aSplitPos = aValue.Search ("|");
11685     if (aSplitPos <= 0)
11686     {
11687       if (!parsePerfStatsFlag (aValue, toReset, aFlagsRem, aFlagsAdd))
11688       {
11689         return Standard_False;
11690       }
11691       if (toReset)
11692       {
11693         theFlags = Graphic3d_RenderingParams::PerfCounters_NONE;
11694       }
11695       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags |  aFlagsAdd);
11696       theFlags = Graphic3d_RenderingParams::PerfCounters(theFlags & ~aFlagsRem);
11697       return Standard_True;
11698     }
11699
11700     if (aSplitPos > 1)
11701     {
11702       TCollection_AsciiString aSubValue = aValue.SubString (1, aSplitPos - 1);
11703       if (!parsePerfStatsFlag (aSubValue, toReset, aFlagsRem, aFlagsAdd))
11704       {
11705         return Standard_False;
11706       }
11707     }
11708     aValue = aValue.SubString (aSplitPos + 1, aValue.Length());
11709   }
11710 }
11711
11712 //=======================================================================
11713 //function : VRenderParams
11714 //purpose  : Enables/disables rendering features
11715 //=======================================================================
11716
11717 static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
11718                                        Standard_Integer  theArgNb,
11719                                        const char**      theArgVec)
11720 {
11721   Handle(V3d_View) aView = ViewerTest::CurrentView();
11722   if (aView.IsNull())
11723   {
11724     Message::SendFail ("Error: no active viewer");
11725     return 1;
11726   }
11727
11728   Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
11729   TCollection_AsciiString aCmdName (theArgVec[0]);
11730   aCmdName.LowerCase();
11731   if (aCmdName == "vraytrace")
11732   {
11733     if (theArgNb == 1)
11734     {
11735       theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "on" : "off") << " ";
11736       return 0;
11737     }
11738     else if (theArgNb == 2)
11739     {
11740       TCollection_AsciiString aValue (theArgVec[1]);
11741       aValue.LowerCase();
11742       if (aValue == "on"
11743        || aValue == "1")
11744       {
11745         aParams.Method = Graphic3d_RM_RAYTRACING;
11746         aView->Redraw();
11747         return 0;
11748       }
11749       else if (aValue == "off"
11750             || aValue == "0")
11751       {
11752         aParams.Method = Graphic3d_RM_RASTERIZATION;
11753         aView->Redraw();
11754         return 0;
11755       }
11756       else
11757       {
11758         Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[1] << "'";
11759         return 1;
11760       }
11761     }
11762     else
11763     {
11764       Message::SendFail ("Syntax error: wrong number of arguments");
11765       return 1;
11766     }
11767   }
11768
11769   if (theArgNb < 2)
11770   {
11771     theDI << "renderMode:  ";
11772     switch (aParams.Method)
11773     {
11774       case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11775       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
11776     }
11777     theDI << "\n";
11778     theDI << "transparency:  ";
11779     switch (aParams.TransparencyMethod)
11780     {
11781       case Graphic3d_RTM_BLEND_UNORDERED: theDI << "Basic blended transparency with non-commuting operator "; break;
11782       case Graphic3d_RTM_BLEND_OIT:       theDI << "Weighted Blended Order-Independent Transparency, depth weight factor: "
11783                                                 << TCollection_AsciiString (aParams.OitDepthFactor); break;
11784       case Graphic3d_RTM_DEPTH_PEELING_OIT: theDI << "Depth Peeling Order-Independent Transparency, Nb.Layers: "
11785                                                 << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers); break;
11786     }
11787     theDI << "\n";
11788     theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
11789     theDI << "rendScale:      " <<  aParams.RenderResolutionScale                       << "\n";
11790     theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
11791     theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
11792     theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
11793     theDI << "shadowMapRes:   " <<  aParams.ShadowMapResolution                         << "\n";
11794     theDI << "shadowMapBias:  " <<  aParams.ShadowMapBias                               << "\n";
11795     theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
11796     theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
11797     theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
11798     theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
11799     theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
11800     theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
11801     theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
11802     theDI << "max radiance:   " <<  aParams.RadianceClampingValue                       << "\n";
11803     theDI << "nb tiles (iss): " <<  aParams.NbRayTracingTiles                           << "\n";
11804     theDI << "tile size (iss):" <<  aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
11805     theDI << "shadingModel: ";
11806     switch (aView->ShadingModel())
11807     {
11808       case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
11809       case Graphic3d_TOSM_UNLIT:     theDI << "unlit";     break;
11810       case Graphic3d_TOSM_FACET:     theDI << "flat";      break;
11811       case Graphic3d_TOSM_VERTEX:    theDI << "gouraud";   break;
11812       case Graphic3d_TOSM_FRAGMENT:  theDI << "phong";     break;
11813       case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
11814       case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
11815     }
11816     theDI << "\n";
11817     {
11818       theDI << "perfCounters:";
11819       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameRate) != 0)
11820       {
11821         theDI << " fps";
11822       }
11823       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_CPU) != 0)
11824       {
11825         theDI << " cpu";
11826       }
11827       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Structures) != 0)
11828       {
11829         theDI << " structs";
11830       }
11831       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Groups) != 0)
11832       {
11833         theDI << " groups";
11834       }
11835       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_GroupArrays) != 0)
11836       {
11837         theDI << " arrays";
11838       }
11839       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Triangles) != 0)
11840       {
11841         theDI << " tris";
11842       }
11843       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Lines) != 0)
11844       {
11845         theDI << " lines";
11846       }
11847       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_Points) != 0)
11848       {
11849         theDI << " pnts";
11850       }
11851       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_EstimMem) != 0)
11852       {
11853         theDI << " gpumem";
11854       }
11855       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_FrameTime) != 0)
11856       {
11857         theDI << " frameTime";
11858       }
11859       if ((aParams.CollectedStats & Graphic3d_RenderingParams::PerfCounters_SkipImmediate) != 0)
11860       {
11861         theDI << " skipimmediate";
11862       }
11863       if (aParams.CollectedStats == Graphic3d_RenderingParams::PerfCounters_NONE)
11864       {
11865         theDI << " none";
11866       }
11867       theDI << "\n";
11868     }
11869     theDI << "depth pre-pass: " << (aParams.ToEnableDepthPrepass        ? "on" : "off") << "\n";
11870     theDI << "alpha to coverage: " << (aParams.ToEnableAlphaToCoverage  ? "on" : "off") << "\n";
11871     theDI << "frustum culling: " << (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On  ? "on" :
11872                                      aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off ? "off" :
11873                                                                                                                     "noUpdate") << "\n";
11874     theDI << "\n";
11875     return 0;
11876   }
11877
11878   bool toPrint = false, toSyncDefaults = false, toSyncAllViews = false;
11879   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
11880   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
11881   {
11882     Standard_CString        anArg (theArgVec[anArgIter]);
11883     TCollection_AsciiString aFlag (anArg);
11884     aFlag.LowerCase();
11885     if (anUpdateTool.parseRedrawMode (aFlag))
11886     {
11887       continue;
11888     }
11889     else if (aFlag == "-echo"
11890           || aFlag == "-print")
11891     {
11892       toPrint = Standard_True;
11893       anUpdateTool.Invalidate();
11894     }
11895     else if (aFlag == "-reset")
11896     {
11897       aParams = ViewerTest::GetViewerFromContext()->DefaultRenderingParams();
11898     }
11899     else if (aFlag == "-sync"
11900           && (anArgIter + 1 < theArgNb))
11901     {
11902       TCollection_AsciiString aSyncFlag (theArgVec[++anArgIter]);
11903       aSyncFlag.LowerCase();
11904       if (aSyncFlag == "default"
11905        || aSyncFlag == "defaults"
11906        || aSyncFlag == "viewer")
11907       {
11908         toSyncDefaults = true;
11909       }
11910       else if (aSyncFlag == "allviews"
11911             || aSyncFlag == "views")
11912       {
11913         toSyncAllViews = true;
11914       }
11915       else
11916       {
11917         Message::SendFail ("Syntax error: unknown parameter to -sync argument");
11918         return 1;
11919       }
11920     }
11921     else if (aFlag == "-mode"
11922           || aFlag == "-rendermode"
11923           || aFlag == "-render_mode")
11924     {
11925       if (toPrint)
11926       {
11927         switch (aParams.Method)
11928         {
11929           case Graphic3d_RM_RASTERIZATION: theDI << "rasterization "; break;
11930           case Graphic3d_RM_RAYTRACING:    theDI << "ray-tracing ";   break;
11931         }
11932         continue;
11933       }
11934       else
11935       {
11936         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11937         return 1;
11938       }
11939     }
11940     else if (aFlag == "-ray"
11941           || aFlag == "-raytrace")
11942     {
11943       if (toPrint)
11944       {
11945         theDI << (aParams.Method == Graphic3d_RM_RAYTRACING ? "true" : "false") << " ";
11946         continue;
11947       }
11948
11949       bool isRayTrace = true;
11950       if (anArgIter + 1 < theArgNb
11951        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRayTrace))
11952       {
11953         ++anArgIter;
11954       }
11955       aParams.Method = isRayTrace ? Graphic3d_RM_RAYTRACING : Graphic3d_RM_RASTERIZATION;
11956     }
11957     else if (aFlag == "-rast"
11958           || aFlag == "-raster"
11959           || aFlag == "-rasterization")
11960     {
11961       if (toPrint)
11962       {
11963         theDI << (aParams.Method == Graphic3d_RM_RASTERIZATION ? "true" : "false") << " ";
11964         continue;
11965       }
11966
11967       bool isRaster = true;
11968       if (anArgIter + 1 < theArgNb
11969        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isRaster))
11970       {
11971         ++anArgIter;
11972       }
11973       aParams.Method = isRaster ? Graphic3d_RM_RASTERIZATION : Graphic3d_RM_RAYTRACING;
11974     }
11975     else if (aFlag == "-msaa")
11976     {
11977       if (toPrint)
11978       {
11979         theDI << aParams.NbMsaaSamples << " ";
11980         continue;
11981       }
11982       else if (++anArgIter >= theArgNb)
11983       {
11984         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
11985         return 1;
11986       }
11987
11988       const Standard_Integer aNbSamples = Draw::Atoi (theArgVec[anArgIter]);
11989       if (aNbSamples < 0)
11990       {
11991         Message::SendFail() << "Syntax error: invalid number of MSAA samples " << aNbSamples << "";
11992         return 1;
11993       }
11994       else
11995       {
11996         aParams.NbMsaaSamples = aNbSamples;
11997       }
11998     }
11999     else if (aFlag == "-linefeather"
12000           || aFlag == "-edgefeather"
12001           || aFlag == "-feather")
12002     {
12003       if (toPrint)
12004       {
12005         theDI << " " << aParams.LineFeather << " ";
12006         continue;
12007       }
12008       else if (++anArgIter >= theArgNb)
12009       {
12010         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12011         return 1;
12012       }
12013
12014       TCollection_AsciiString aParam = theArgVec[anArgIter];
12015       const Standard_ShortReal aFeather = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
12016       if (aFeather <= 0.0f)
12017       {
12018         Message::SendFail() << "Syntax error: invalid value of line width feather " << aFeather << ". Should be > 0";
12019         return 1;
12020       }
12021       aParams.LineFeather = aFeather;
12022     }
12023     else if (aFlag == "-oit")
12024     {
12025       if (toPrint)
12026       {
12027         if (aParams.TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
12028         {
12029           theDI << "on, depth weight factor: " << TCollection_AsciiString (aParams.OitDepthFactor) << " ";
12030         }
12031         else if (aParams.TransparencyMethod == Graphic3d_RTM_DEPTH_PEELING_OIT)
12032         {
12033           theDI << "on, depth peeling layers: " << TCollection_AsciiString (aParams.NbOitDepthPeelingLayers) << " ";
12034         }
12035         else
12036         {
12037           theDI << "off" << " ";
12038         }
12039         continue;
12040       }
12041       else if (++anArgIter >= theArgNb)
12042       {
12043         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12044         return 1;
12045       }
12046
12047       TCollection_AsciiString aParam = theArgVec[anArgIter];
12048       aParam.LowerCase();
12049       if (aParam == "peeling"
12050        || aParam == "peel")
12051       {
12052         aParams.TransparencyMethod = Graphic3d_RTM_DEPTH_PEELING_OIT;
12053         if (anArgIter + 1 < theArgNb
12054          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsIntegerValue())
12055         {
12056           ++anArgIter;
12057           const Standard_Integer aNbLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
12058           if (aNbLayers < 2)
12059           {
12060             Message::SendFail() << "Syntax error: invalid layers number specified for Depth Peeling OIT " << aNbLayers;
12061             return 1;
12062           }
12063           aParams.NbOitDepthPeelingLayers = TCollection_AsciiString (theArgVec[anArgIter]).IntegerValue();
12064         }
12065       }
12066       else if (aParam == "weighted"
12067             || aParam == "weight")
12068       {
12069         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
12070         if (anArgIter + 1 < theArgNb
12071          && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
12072         {
12073           ++anArgIter;
12074           const Standard_ShortReal aWeight = (Standard_ShortReal)TCollection_AsciiString (theArgVec[anArgIter]).RealValue();
12075           if (aWeight < 0.f || aWeight > 1.f)
12076           {
12077             Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
12078             return 1;
12079           }
12080           aParams.OitDepthFactor = aWeight;
12081         }
12082       }
12083       else if (aParam.IsRealValue())
12084       {
12085         const Standard_ShortReal aWeight = (Standard_ShortReal) Draw::Atof (theArgVec[anArgIter]);
12086         if (aWeight < 0.f || aWeight > 1.f)
12087         {
12088           Message::SendFail() << "Syntax error: invalid value of Weighted Order-Independent Transparency depth weight factor " << aWeight << ". Should be within range [0.0; 1.0]";
12089           return 1;
12090         }
12091
12092         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_OIT;
12093         aParams.OitDepthFactor     = aWeight;
12094       }
12095       else if (aParam == "off")
12096       {
12097         aParams.TransparencyMethod = Graphic3d_RTM_BLEND_UNORDERED;
12098       }
12099       else
12100       {
12101         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12102         return 1;
12103       }
12104     }
12105     else if (aFlag == "-depthprepass")
12106     {
12107       if (toPrint)
12108       {
12109         theDI << (aParams.ToEnableDepthPrepass ? "on " : "off ");
12110         continue;
12111       }
12112       aParams.ToEnableDepthPrepass = Standard_True;
12113       if (anArgIter + 1 < theArgNb
12114        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableDepthPrepass))
12115       {
12116         ++anArgIter;
12117       }
12118     }
12119     else if (aFlag == "-samplealphatocoverage"
12120           || aFlag == "-alphatocoverage")
12121     {
12122       if (toPrint)
12123       {
12124         theDI << (aParams.ToEnableAlphaToCoverage ? "on " : "off ");
12125         continue;
12126       }
12127       aParams.ToEnableAlphaToCoverage = Standard_True;
12128       if (anArgIter + 1 < theArgNb
12129        && Draw::ParseOnOff (theArgVec[anArgIter + 1], aParams.ToEnableAlphaToCoverage))
12130       {
12131         ++anArgIter;
12132       }
12133     }
12134     else if (aFlag == "-rendscale"
12135           || aFlag == "-renderscale"
12136           || aFlag == "-renderresolutionscale")
12137     {
12138       if (toPrint)
12139       {
12140         theDI << aParams.RenderResolutionScale << " ";
12141         continue;
12142       }
12143       else if (++anArgIter >= theArgNb)
12144       {
12145         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12146         return 1;
12147       }
12148
12149       const Standard_Real aScale = Draw::Atof (theArgVec[anArgIter]);
12150       if (aScale < 0.01)
12151       {
12152         Message::SendFail() << "Syntax error: invalid rendering resolution scale " << aScale << "";
12153         return 1;
12154       }
12155       else
12156       {
12157         aParams.RenderResolutionScale = Standard_ShortReal(aScale);
12158       }
12159     }
12160     else if (aFlag == "-raydepth"
12161           || aFlag == "-ray_depth")
12162     {
12163       if (toPrint)
12164       {
12165         theDI << aParams.RaytracingDepth << " ";
12166         continue;
12167       }
12168       else if (++anArgIter >= theArgNb)
12169       {
12170         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12171         return 1;
12172       }
12173
12174       const Standard_Integer aDepth = Draw::Atoi (theArgVec[anArgIter]);
12175
12176       // We allow RaytracingDepth be more than 10 in case of GI enabled
12177       if (aDepth < 1 || (aDepth > 10 && !aParams.IsGlobalIlluminationEnabled))
12178       {
12179         Message::SendFail() << "Syntax error: invalid ray-tracing depth " << aDepth << ". Should be within range [1; 10]";
12180         return 1;
12181       }
12182       else
12183       {
12184         aParams.RaytracingDepth = aDepth;
12185       }
12186     }
12187     else if (aFlag == "-shad"
12188           || aFlag == "-shadows")
12189     {
12190       if (toPrint)
12191       {
12192         theDI << (aParams.IsShadowEnabled ? "on" : "off") << " ";
12193         continue;
12194       }
12195
12196       Standard_Boolean toEnable = Standard_True;
12197       if (++anArgIter < theArgNb
12198       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12199       {
12200         --anArgIter;
12201       }
12202       aParams.IsShadowEnabled = toEnable;
12203     }
12204     else if (aFlag == "-shadowmapresolution"
12205           || aFlag == "-shadowmap")
12206     {
12207       if (toPrint)
12208       {
12209         theDI << aParams.ShadowMapResolution << " ";
12210         continue;
12211       }
12212       else if (++anArgIter >= theArgNb)
12213       {
12214         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12215         return 1;
12216       }
12217
12218       aParams.ShadowMapResolution = Draw::Atoi (theArgVec[anArgIter]);
12219     }
12220     else if (aFlag == "-shadowmapbias")
12221     {
12222       if (toPrint)
12223       {
12224         theDI << aParams.ShadowMapBias << " ";
12225         continue;
12226       }
12227       else if (++anArgIter >= theArgNb)
12228       {
12229         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12230         return 1;
12231       }
12232
12233       aParams.ShadowMapBias = (float )Draw::Atof (theArgVec[anArgIter]);
12234     }
12235     else if (aFlag == "-refl"
12236           || aFlag == "-reflections")
12237     {
12238       if (toPrint)
12239       {
12240         theDI << (aParams.IsReflectionEnabled ? "on" : "off") << " ";
12241         continue;
12242       }
12243
12244       Standard_Boolean toEnable = Standard_True;
12245       if (++anArgIter < theArgNb
12246       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12247       {
12248         --anArgIter;
12249       }
12250       aParams.IsReflectionEnabled = toEnable;
12251     }
12252     else if (aFlag == "-fsaa")
12253     {
12254       if (toPrint)
12255       {
12256         theDI << (aParams.IsAntialiasingEnabled ? "on" : "off") << " ";
12257         continue;
12258       }
12259
12260       Standard_Boolean toEnable = Standard_True;
12261       if (++anArgIter < theArgNb
12262       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12263       {
12264         --anArgIter;
12265       }
12266       aParams.IsAntialiasingEnabled = toEnable;
12267     }
12268     else if (aFlag == "-gleam")
12269     {
12270       if (toPrint)
12271       {
12272         theDI << (aParams.IsTransparentShadowEnabled ? "on" : "off") << " ";
12273         continue;
12274       }
12275
12276       Standard_Boolean toEnable = Standard_True;
12277       if (++anArgIter < theArgNb
12278       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12279       {
12280         --anArgIter;
12281       }
12282       aParams.IsTransparentShadowEnabled = toEnable;
12283     }
12284     else if (aFlag == "-gi")
12285     {
12286       if (toPrint)
12287       {
12288         theDI << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << " ";
12289         continue;
12290       }
12291
12292       Standard_Boolean toEnable = Standard_True;
12293       if (++anArgIter < theArgNb
12294       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12295       {
12296         --anArgIter;
12297       }
12298       aParams.IsGlobalIlluminationEnabled = toEnable;
12299       if (!toEnable)
12300       {
12301         aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
12302       }
12303     }
12304     else if (aFlag == "-blockedrng"
12305           || aFlag == "-brng")
12306     {
12307       if (toPrint)
12308       {
12309         theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
12310         continue;
12311       }
12312
12313       Standard_Boolean toEnable = Standard_True;
12314       if (++anArgIter < theArgNb
12315         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12316       {
12317         --anArgIter;
12318       }
12319       aParams.CoherentPathTracingMode = toEnable;
12320     }
12321     else if (aFlag == "-maxrad")
12322     {
12323       if (toPrint)
12324       {
12325         theDI << aParams.RadianceClampingValue << " ";
12326         continue;
12327       }
12328       else if (++anArgIter >= theArgNb)
12329       {
12330         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12331         return 1;
12332       }
12333
12334       const TCollection_AsciiString aMaxRadStr = theArgVec[anArgIter];
12335       if (!aMaxRadStr.IsRealValue (Standard_True))
12336       {
12337         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12338         return 1;
12339       }
12340
12341       const Standard_Real aMaxRadiance = aMaxRadStr.RealValue();
12342       if (aMaxRadiance <= 0.0)
12343       {
12344         Message::SendFail() << "Syntax error: invalid radiance clamping value " << aMaxRadiance;
12345         return 1;
12346       }
12347       else
12348       {
12349         aParams.RadianceClampingValue = static_cast<Standard_ShortReal> (aMaxRadiance);
12350       }
12351     }
12352     else if (aFlag == "-iss")
12353     {
12354       if (toPrint)
12355       {
12356         theDI << (aParams.AdaptiveScreenSampling ? "on" : "off") << " ";
12357         continue;
12358       }
12359
12360       Standard_Boolean toEnable = Standard_True;
12361       if (++anArgIter < theArgNb
12362         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12363       {
12364         --anArgIter;
12365       }
12366       aParams.AdaptiveScreenSampling = toEnable;
12367     }
12368     else if (aFlag == "-issatomic")
12369     {
12370       if (toPrint)
12371       {
12372         theDI << (aParams.AdaptiveScreenSamplingAtomic ? "on" : "off") << " ";
12373         continue;
12374       }
12375
12376       Standard_Boolean toEnable = Standard_True;
12377       if (++anArgIter < theArgNb
12378       && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12379       {
12380         --anArgIter;
12381       }
12382       aParams.AdaptiveScreenSamplingAtomic = toEnable;
12383     }
12384     else if (aFlag == "-issd")
12385     {
12386       if (toPrint)
12387       {
12388         theDI << (aParams.ShowSamplingTiles ? "on" : "off") << " ";
12389         continue;
12390       }
12391
12392       Standard_Boolean toEnable = Standard_True;
12393       if (++anArgIter < theArgNb
12394         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12395       {
12396         --anArgIter;
12397       }
12398       aParams.ShowSamplingTiles = toEnable;
12399     }
12400     else if (aFlag == "-tilesize")
12401     {
12402       if (toPrint)
12403       {
12404         theDI << aParams.RayTracingTileSize << " ";
12405         continue;
12406       }
12407       else if (++anArgIter >= theArgNb)
12408       {
12409         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12410         return 1;
12411       }
12412
12413       const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
12414       if (aTileSize < 1)
12415       {
12416         Message::SendFail() << "Syntax error: invalid size of ISS tile " << aTileSize;
12417         return 1;
12418       }
12419       aParams.RayTracingTileSize = aTileSize;
12420     }
12421     else if (aFlag == "-nbtiles")
12422     {
12423       if (toPrint)
12424       {
12425         theDI << aParams.NbRayTracingTiles << " ";
12426         continue;
12427       }
12428       else if (++anArgIter >= theArgNb)
12429       {
12430         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12431         return 1;
12432       }
12433
12434       const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
12435       if (aNbTiles < -1)
12436       {
12437         Message::SendFail() << "Syntax error: invalid number of ISS tiles " << aNbTiles;
12438         return 1;
12439       }
12440       else if (aNbTiles > 0
12441             && (aNbTiles < 64
12442              || aNbTiles > 1024))
12443       {
12444         Message::SendWarning() << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].";
12445       }
12446       aParams.NbRayTracingTiles = aNbTiles;
12447     }
12448     else if (aFlag == "-env")
12449     {
12450       if (toPrint)
12451       {
12452         theDI << (aParams.UseEnvironmentMapBackground ? "on" : "off") << " ";
12453         continue;
12454       }
12455
12456       Standard_Boolean toEnable = Standard_True;
12457       if (++anArgIter < theArgNb
12458         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12459       {
12460         --anArgIter;
12461       }
12462       aParams.UseEnvironmentMapBackground = toEnable;
12463     }
12464     else if (aFlag == "-ignorenormalmap")
12465     {
12466       if (toPrint)
12467       {
12468         theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " ";
12469         continue;
12470       }
12471
12472       Standard_Boolean toEnable = Standard_True;
12473       if (++anArgIter < theArgNb
12474         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12475       {
12476         --anArgIter;
12477       }
12478       aParams.ToIgnoreNormalMapInRayTracing = toEnable;
12479     }
12480     else if (aFlag == "-twoside")
12481     {
12482       if (toPrint)
12483       {
12484         theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
12485         continue;
12486       }
12487
12488       Standard_Boolean toEnable = Standard_True;
12489       if (++anArgIter < theArgNb
12490         && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12491       {
12492         --anArgIter;
12493       }
12494       aParams.TwoSidedBsdfModels = toEnable;
12495     }
12496     else if (aFlag == "-shademodel"
12497           || aFlag == "-shadingmodel"
12498           || aFlag == "-shading")
12499     {
12500       if (toPrint)
12501       {
12502         switch (aView->ShadingModel())
12503         {
12504           case Graphic3d_TOSM_DEFAULT:   theDI << "default";   break;
12505           case Graphic3d_TOSM_UNLIT:     theDI << "unlit ";    break;
12506           case Graphic3d_TOSM_FACET:     theDI << "flat ";     break;
12507           case Graphic3d_TOSM_VERTEX:    theDI << "gouraud ";  break;
12508           case Graphic3d_TOSM_FRAGMENT:  theDI << "phong ";    break;
12509           case Graphic3d_TOSM_PBR:       theDI << "pbr";       break;
12510           case Graphic3d_TOSM_PBR_FACET: theDI << "pbr_facet"; break;
12511         }
12512         continue;
12513       }
12514
12515       if (++anArgIter >= theArgNb)
12516       {
12517         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12518       }
12519
12520       Graphic3d_TypeOfShadingModel aModel = Graphic3d_TOSM_DEFAULT;
12521       if (ViewerTest::ParseShadingModel (theArgVec[anArgIter], aModel)
12522        && aModel != Graphic3d_TOSM_DEFAULT)
12523       {
12524         aView->SetShadingModel (aModel);
12525       }
12526       else
12527       {
12528         Message::SendFail() << "Syntax error: unknown shading model '" << theArgVec[anArgIter] << "'";
12529         return 1;
12530       }
12531     }
12532     else if (aFlag == "-pbrenvpow2size"
12533           || aFlag == "-pbrenvp2s"
12534           || aFlag == "-pep2s")
12535     {
12536       if (++anArgIter >= theArgNb)
12537       {
12538         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12539         return 1;
12540       }
12541
12542       const Standard_Integer aPbrEnvPow2Size = Draw::Atoi (theArgVec[anArgIter]);
12543       if (aPbrEnvPow2Size < 1)
12544       {
12545         Message::SendFail ("Syntax error: 'Pow2Size' of PBR Environment has to be greater or equal 1");
12546         return 1;
12547       }
12548       aParams.PbrEnvPow2Size = aPbrEnvPow2Size;
12549     }
12550     else if (aFlag == "-pbrenvspecmaplevelsnumber"
12551           || aFlag == "-pbrenvspecmapnblevels"
12552           || aFlag == "-pbrenvspecmaplevels"
12553           || aFlag == "-pbrenvsmln"
12554           || aFlag == "-pesmln")
12555     {
12556       if (++anArgIter >= theArgNb)
12557       {
12558         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12559         return 1;
12560       }
12561
12562       const Standard_Integer aPbrEnvSpecMapNbLevels = Draw::Atoi (theArgVec[anArgIter]);
12563       if (aPbrEnvSpecMapNbLevels < 2)
12564       {
12565         Message::SendFail ("Syntax error: 'SpecMapLevelsNumber' of PBR Environment has to be greater or equal 2");
12566         return 1;
12567       }
12568       aParams.PbrEnvSpecMapNbLevels = aPbrEnvSpecMapNbLevels;
12569     }
12570     else if (aFlag == "-pbrenvbakngdiffsamplesnumber"
12571           || aFlag == "-pbrenvbakingdiffsamples"
12572           || aFlag == "-pbrenvbdsn")
12573     {
12574       if (++anArgIter >= theArgNb)
12575       {
12576         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12577         return 1;
12578       }
12579
12580       const Standard_Integer aPbrEnvBakingDiffNbSamples = Draw::Atoi (theArgVec[anArgIter]);
12581       if (aPbrEnvBakingDiffNbSamples < 1)
12582       {
12583         Message::SendFail ("Syntax error: 'BakingDiffSamplesNumber' of PBR Environment has to be greater or equal 1");
12584         return 1;
12585       }
12586       aParams.PbrEnvBakingDiffNbSamples = aPbrEnvBakingDiffNbSamples;
12587     }
12588     else if (aFlag == "-pbrenvbakngspecsamplesnumber"
12589           || aFlag == "-pbrenvbakingspecsamples"
12590           || aFlag == "-pbrenvbssn")
12591     {
12592     if (++anArgIter >= theArgNb)
12593     {
12594       Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12595       return 1;
12596     }
12597
12598     const Standard_Integer aPbrEnvBakingSpecNbSamples = Draw::Atoi(theArgVec[anArgIter]);
12599     if (aPbrEnvBakingSpecNbSamples < 1)
12600     {
12601       Message::SendFail ("Syntax error: 'BakingSpecSamplesNumber' of PBR Environment has to be greater or equal 1");
12602       return 1;
12603     }
12604     aParams.PbrEnvBakingSpecNbSamples = aPbrEnvBakingSpecNbSamples;
12605     }
12606     else if (aFlag == "-pbrenvbakingprobability"
12607           || aFlag == "-pbrenvbp")
12608     {
12609       if (++anArgIter >= theArgNb)
12610       {
12611         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12612         return 1;
12613       }
12614       const Standard_ShortReal aPbrEnvBakingProbability = static_cast<Standard_ShortReal>(Draw::Atof (theArgVec[anArgIter]));
12615       if (aPbrEnvBakingProbability < 0.f
12616        || aPbrEnvBakingProbability > 1.f)
12617       {
12618         Message::SendFail ("Syntax error: 'BakingProbability' of PBR Environment has to be in range of [0, 1]");
12619         return 1;
12620       }
12621       aParams.PbrEnvBakingProbability = aPbrEnvBakingProbability;
12622     }
12623     else if (aFlag == "-resolution")
12624     {
12625       if (++anArgIter >= theArgNb)
12626       {
12627         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12628         return 1;
12629       }
12630
12631       TCollection_AsciiString aResolution (theArgVec[anArgIter]);
12632       if (aResolution.IsIntegerValue())
12633       {
12634         aView->ChangeRenderingParams().Resolution = static_cast<unsigned int> (Draw::Atoi (aResolution.ToCString()));
12635       }
12636       else
12637       {
12638         Message::SendFail() << "Syntax error: wrong syntax at argument'" << anArg << "'";
12639         return 1;
12640       }
12641     }
12642     else if (aFlag == "-rebuildglsl"
12643           || aFlag == "-rebuild")
12644     {
12645       if (toPrint)
12646       {
12647         theDI << (aParams.RebuildRayTracingShaders ? "on" : "off") << " ";
12648         continue;
12649       }
12650
12651       Standard_Boolean toEnable = Standard_True;
12652       if (++anArgIter < theArgNb
12653           && !Draw::ParseOnOff (theArgVec[anArgIter], toEnable))
12654       {
12655         --anArgIter;
12656       }
12657       aParams.RebuildRayTracingShaders = toEnable;
12658     }
12659     else if (aFlag == "-focal")
12660     {
12661       if (++anArgIter >= theArgNb)
12662       {
12663         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12664         return 1;
12665       }
12666
12667       TCollection_AsciiString aParam (theArgVec[anArgIter]);
12668       if (aParam.IsRealValue (Standard_True))
12669       {
12670         float aFocalDist = static_cast<float> (aParam.RealValue());
12671         if (aFocalDist < 0)
12672         {
12673           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12674           return 1;
12675         }
12676         aView->ChangeRenderingParams().CameraFocalPlaneDist = aFocalDist;
12677       }
12678       else
12679       {
12680         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12681         return 1;
12682       }
12683     }
12684     else if (aFlag == "-aperture")
12685     {
12686       if (++anArgIter >= theArgNb)
12687       {
12688         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12689         return 1;
12690       }
12691
12692       TCollection_AsciiString aParam(theArgVec[anArgIter]);
12693       if (aParam.IsRealValue (Standard_True))
12694       {
12695         float aApertureSize = static_cast<float> (aParam.RealValue());
12696         if (aApertureSize < 0)
12697         {
12698           Message::SendFail() << "Error: parameter can't be negative at argument '" << anArg << "'";
12699           return 1;
12700         }
12701         aView->ChangeRenderingParams().CameraApertureRadius = aApertureSize;
12702       }
12703       else
12704       {
12705         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12706         return 1;
12707       }
12708     }
12709     else if (aFlag == "-exposure")
12710     {
12711       if (++anArgIter >= theArgNb)
12712       {
12713         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12714         return 1;
12715       }
12716
12717       TCollection_AsciiString anExposure (theArgVec[anArgIter]);
12718       if (anExposure.IsRealValue (Standard_True))
12719       {
12720         aView->ChangeRenderingParams().Exposure = static_cast<float> (anExposure.RealValue());
12721       }
12722       else
12723       {
12724         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12725         return 1;
12726       }
12727     }
12728     else if (aFlag == "-whitepoint")
12729     {
12730       if (++anArgIter >= theArgNb)
12731       {
12732         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12733         return 1;
12734       }
12735
12736       TCollection_AsciiString aWhitePoint (theArgVec[anArgIter]);
12737       if (aWhitePoint.IsRealValue (Standard_True))
12738       {
12739         aView->ChangeRenderingParams().WhitePoint = static_cast<float> (aWhitePoint.RealValue());
12740       }
12741       else
12742       {
12743         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12744         return 1;
12745       }
12746     }
12747     else if (aFlag == "-tonemapping")
12748     {
12749       if (++anArgIter >= theArgNb)
12750       {
12751         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12752         return 1;
12753       }
12754
12755       TCollection_AsciiString aMode (theArgVec[anArgIter]);
12756       aMode.LowerCase();
12757
12758       if (aMode == "disabled")
12759       {
12760         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Disabled;
12761       }
12762       else if (aMode == "filmic")
12763       {
12764         aView->ChangeRenderingParams().ToneMappingMethod = Graphic3d_ToneMappingMethod_Filmic;
12765       }
12766       else
12767       {
12768         Message::SendFail() << "Syntax error at argument'" << anArg << "'";
12769         return 1;
12770       }
12771     }
12772     else if (aFlag == "-performancestats"
12773           || aFlag == "-performancecounters"
12774           || aFlag == "-perfstats"
12775           || aFlag == "-perfcounters"
12776           || aFlag == "-stats")
12777     {
12778       if (++anArgIter >= theArgNb)
12779       {
12780         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12781         return 1;
12782       }
12783
12784       TCollection_AsciiString aFlagsStr (theArgVec[anArgIter]);
12785       aFlagsStr.LowerCase();
12786       Graphic3d_RenderingParams::PerfCounters aFlags = aView->ChangeRenderingParams().CollectedStats;
12787       if (!convertToPerfStatsFlags (aFlagsStr, aFlags))
12788       {
12789         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12790         return 1;
12791       }
12792       aView->ChangeRenderingParams().CollectedStats = aFlags;
12793       aView->ChangeRenderingParams().ToShowStats = aFlags != Graphic3d_RenderingParams::PerfCounters_NONE;
12794     }
12795     else if (aFlag == "-perfupdateinterval"
12796           || aFlag == "-statsupdateinterval")
12797     {
12798       if (++anArgIter >= theArgNb)
12799       {
12800         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12801         return 1;
12802       }
12803       aView->ChangeRenderingParams().StatsUpdateInterval = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12804     }
12805     else if (aFlag == "-perfchart"
12806           || aFlag == "-statschart")
12807     {
12808       if (++anArgIter >= theArgNb)
12809       {
12810         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12811         return 1;
12812       }
12813       aView->ChangeRenderingParams().StatsNbFrames = Draw::Atoi (theArgVec[anArgIter]);
12814     }
12815     else if (aFlag == "-perfchartmax"
12816           || aFlag == "-statschartmax")
12817     {
12818       if (++anArgIter >= theArgNb)
12819       {
12820         Message::SendFail() << "Syntax error at argument '" << anArg << "'";
12821         return 1;
12822       }
12823       aView->ChangeRenderingParams().StatsMaxChartTime = (Standard_ShortReal )Draw::Atof (theArgVec[anArgIter]);
12824     }
12825     else if (aFlag == "-frustumculling"
12826           || aFlag == "-culling")
12827     {
12828       if (toPrint)
12829       {
12830         theDI << ((aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_On)  ? "on" :
12831                   (aParams.FrustumCullingState == Graphic3d_RenderingParams::FrustumCulling_Off) ? "off" :
12832                                                                                                    "noUpdate") << " ";
12833         continue;
12834       }
12835
12836       Graphic3d_RenderingParams::FrustumCulling aState = Graphic3d_RenderingParams::FrustumCulling_On;
12837       if (++anArgIter < theArgNb)
12838       {
12839         TCollection_AsciiString aStateStr(theArgVec[anArgIter]);
12840         aStateStr.LowerCase();
12841         bool toEnable = true;
12842         if (Draw::ParseOnOff (aStateStr.ToCString(), toEnable))
12843         {
12844           aState = toEnable ? Graphic3d_RenderingParams::FrustumCulling_On : Graphic3d_RenderingParams::FrustumCulling_Off;
12845         }
12846         else if (aStateStr == "noupdate"
12847               || aStateStr == "freeze")
12848         {
12849           aState = Graphic3d_RenderingParams::FrustumCulling_NoUpdate;
12850         }
12851         else
12852         {
12853           --anArgIter;
12854         }
12855       }
12856       aParams.FrustumCullingState = aState;
12857     }
12858     else
12859     {
12860       Message::SendFail() << "Syntax error: unknown flag '" << anArg << "'";
12861       return 1;
12862     }
12863   }
12864
12865   // set current view parameters as defaults
12866   if (toSyncDefaults)
12867   {
12868     ViewerTest::GetViewerFromContext()->SetDefaultRenderingParams (aParams);
12869   }
12870   if (toSyncAllViews)
12871   {
12872     for (V3d_ListOfViewIterator aViewIter = ViewerTest::GetViewerFromContext()->DefinedViewIterator(); aViewIter.More(); aViewIter.Next())
12873     {
12874       aViewIter.Value()->ChangeRenderingParams() = aParams;
12875     }
12876   }
12877   return 0;
12878 }
12879
12880 //=======================================================================
12881 //function : searchInfo
12882 //purpose  :
12883 //=======================================================================
12884 inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
12885                                            const TCollection_AsciiString&              theKey)
12886 {
12887   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
12888   {
12889     if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
12890     {
12891       return anIter.Value();
12892     }
12893   }
12894   return TCollection_AsciiString();
12895 }
12896
12897 //=======================================================================
12898 //function : VStatProfiler
12899 //purpose  :
12900 //=======================================================================
12901 static Standard_Integer VStatProfiler (Draw_Interpretor& theDI,
12902                                        Standard_Integer  theArgNb,
12903                                        const char**      theArgVec)
12904 {
12905   Handle(V3d_View) aView = ViewerTest::CurrentView();
12906   if (aView.IsNull())
12907   {
12908     Message::SendFail ("Error: no active viewer");
12909     return 1;
12910   }
12911
12912   Standard_Boolean toRedraw = Standard_True;
12913   Graphic3d_RenderingParams::PerfCounters aPrevCounters = aView->ChangeRenderingParams().CollectedStats;
12914   Standard_ShortReal aPrevUpdInterval = aView->ChangeRenderingParams().StatsUpdateInterval;
12915   Graphic3d_RenderingParams::PerfCounters aRenderParams = Graphic3d_RenderingParams::PerfCounters_NONE;
12916   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12917   {
12918     Standard_CString        anArg (theArgVec[anArgIter]);
12919     TCollection_AsciiString aFlag (anArg);
12920     aFlag.LowerCase();
12921     if (aFlag == "-noredraw")
12922     {
12923       toRedraw = Standard_False;
12924     }
12925     else
12926     {
12927       Graphic3d_RenderingParams::PerfCounters aParam = Graphic3d_RenderingParams::PerfCounters_NONE;
12928       if      (aFlag == "fps")        aParam = Graphic3d_RenderingParams::PerfCounters_FrameRate;
12929       else if (aFlag == "cpu")        aParam = Graphic3d_RenderingParams::PerfCounters_CPU;
12930       else if (aFlag == "alllayers"
12931             || aFlag == "layers")     aParam = Graphic3d_RenderingParams::PerfCounters_Layers;
12932       else if (aFlag == "allstructs"
12933             || aFlag == "allstructures"
12934             || aFlag == "structs"
12935             || aFlag == "structures") aParam = Graphic3d_RenderingParams::PerfCounters_Structures;
12936       else if (aFlag == "groups")     aParam = Graphic3d_RenderingParams::PerfCounters_Groups;
12937       else if (aFlag == "allarrays"
12938             || aFlag == "fillarrays"
12939             || aFlag == "linearrays"
12940             || aFlag == "pointarrays"
12941             || aFlag == "textarrays") aParam = Graphic3d_RenderingParams::PerfCounters_GroupArrays;
12942       else if (aFlag == "triangles")  aParam = Graphic3d_RenderingParams::PerfCounters_Triangles;
12943       else if (aFlag == "lines")      aParam = Graphic3d_RenderingParams::PerfCounters_Lines;
12944       else if (aFlag == "points")     aParam = Graphic3d_RenderingParams::PerfCounters_Points;
12945       else if (aFlag == "geommem"
12946             || aFlag == "texturemem"
12947             || aFlag == "framemem")   aParam = Graphic3d_RenderingParams::PerfCounters_EstimMem;
12948       else if (aFlag == "elapsedframe"
12949             || aFlag == "cpuframeaverage"
12950             || aFlag == "cpupickingaverage"
12951             || aFlag == "cpucullingaverage"
12952             || aFlag == "cpudynaverage"
12953             || aFlag == "cpuframemax"
12954             || aFlag == "cpupickingmax"
12955             || aFlag == "cpucullingmax"
12956             || aFlag == "cpudynmax")  aParam = Graphic3d_RenderingParams::PerfCounters_FrameTime;
12957       else
12958       {
12959         Message::SendFail() << "Error: unknown argument '" << theArgVec[anArgIter] << "'";
12960         continue;
12961       }
12962
12963       aRenderParams = Graphic3d_RenderingParams::PerfCounters (aRenderParams | aParam);
12964     }
12965   }
12966
12967   if (aRenderParams != Graphic3d_RenderingParams::PerfCounters_NONE)
12968   {
12969     aView->ChangeRenderingParams().CollectedStats =
12970       Graphic3d_RenderingParams::PerfCounters (aView->RenderingParams().CollectedStats | aRenderParams);
12971
12972     if (toRedraw)
12973     {
12974       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
12975       aView->Redraw();
12976       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
12977     }
12978
12979     TColStd_IndexedDataMapOfStringString aDict;
12980     aView->StatisticInformation (aDict);
12981
12982     aView->ChangeRenderingParams().CollectedStats = aPrevCounters;
12983
12984     for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
12985     {
12986       Standard_CString        anArg(theArgVec[anArgIter]);
12987       TCollection_AsciiString aFlag(anArg);
12988       aFlag.LowerCase();
12989       if (aFlag == "fps")
12990       {
12991         theDI << searchInfo (aDict, "FPS") << " ";
12992       }
12993       else if (aFlag == "cpu")
12994       {
12995         theDI << searchInfo (aDict, "CPU FPS") << " ";
12996       }
12997       else if (aFlag == "alllayers")
12998       {
12999         theDI << searchInfo (aDict, "Layers") << " ";
13000       }
13001       else if (aFlag == "layers")
13002       {
13003         theDI << searchInfo (aDict, "Rendered layers") << " ";
13004       }
13005       else if (aFlag == "allstructs"
13006             || aFlag == "allstructures")
13007       {
13008         theDI << searchInfo (aDict, "Structs") << " ";
13009       }
13010       else if (aFlag == "structs"
13011             || aFlag == "structures")
13012       {
13013         TCollection_AsciiString aRend = searchInfo (aDict, "Rendered structs");
13014         if (aRend.IsEmpty()) // all structures rendered
13015         {
13016           aRend = searchInfo (aDict, "Structs");
13017         }
13018         theDI << aRend << " ";
13019       }
13020       else if (aFlag == "groups")
13021       {
13022         theDI << searchInfo (aDict, "Rendered groups") << " ";
13023       }
13024       else if (aFlag == "allarrays")
13025       {
13026         theDI << searchInfo (aDict, "Rendered arrays") << " ";
13027       }
13028       else if (aFlag == "fillarrays")
13029       {
13030         theDI << searchInfo (aDict, "Rendered [fill] arrays") << " ";
13031       }
13032       else if (aFlag == "linearrays")
13033       {
13034         theDI << searchInfo (aDict, "Rendered [line] arrays") << " ";
13035       }
13036       else if (aFlag == "pointarrays")
13037       {
13038         theDI << searchInfo (aDict, "Rendered [point] arrays") << " ";
13039       }
13040       else if (aFlag == "textarrays")
13041       {
13042         theDI << searchInfo (aDict, "Rendered [text] arrays") << " ";
13043       }
13044       else if (aFlag == "triangles")
13045       {
13046         theDI << searchInfo (aDict, "Rendered triangles") << " ";
13047       }
13048       else if (aFlag == "points")
13049       {
13050         theDI << searchInfo (aDict, "Rendered points") << " ";
13051       }
13052       else if (aFlag == "geommem")
13053       {
13054         theDI << searchInfo (aDict, "GPU Memory [geometry]") << " ";
13055       }
13056       else if (aFlag == "texturemem")
13057       {
13058         theDI << searchInfo (aDict, "GPU Memory [textures]") << " ";
13059       }
13060       else if (aFlag == "framemem")
13061       {
13062         theDI << searchInfo (aDict, "GPU Memory [frames]") << " ";
13063       }
13064       else if (aFlag == "elapsedframe")
13065       {
13066         theDI << searchInfo (aDict, "Elapsed Frame (average)") << " ";
13067       }
13068       else if (aFlag == "cpuframe_average")
13069       {
13070         theDI << searchInfo (aDict, "CPU Frame (average)") << " ";
13071       }
13072       else if (aFlag == "cpupicking_average")
13073       {
13074         theDI << searchInfo (aDict, "CPU Picking (average)") << " ";
13075       }
13076       else if (aFlag == "cpuculling_average")
13077       {
13078         theDI << searchInfo (aDict, "CPU Culling (average)") << " ";
13079       }
13080       else if (aFlag == "cpudyn_average")
13081       {
13082         theDI << searchInfo (aDict, "CPU Dynamics (average)") << " ";
13083       }
13084       else if (aFlag == "cpuframe_max")
13085       {
13086         theDI << searchInfo (aDict, "CPU Frame (max)") << " ";
13087       }
13088       else if (aFlag == "cpupicking_max")
13089       {
13090         theDI << searchInfo (aDict, "CPU Picking (max)") << " ";
13091       }
13092       else if (aFlag == "cpuculling_max")
13093       {
13094         theDI << searchInfo (aDict, "CPU Culling (max)") << " ";
13095       }
13096       else if (aFlag == "cpudyn_max")
13097       {
13098         theDI << searchInfo (aDict, "CPU Dynamics (max)") << " ";
13099       }
13100     }
13101   }
13102   else
13103   {
13104     if (toRedraw)
13105     {
13106       aView->ChangeRenderingParams().StatsUpdateInterval = -1;
13107       aView->Redraw();
13108       aView->ChangeRenderingParams().StatsUpdateInterval = aPrevUpdInterval;
13109     }
13110     theDI << "Statistic info:\n" << aView->StatisticInformation();
13111   }
13112   return 0;
13113 }
13114
13115 //=======================================================================
13116 //function : VXRotate
13117 //purpose  :
13118 //=======================================================================
13119 static Standard_Integer VXRotate (Draw_Interpretor& di,
13120                                    Standard_Integer argc,
13121                                    const char ** argv)
13122 {
13123   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
13124   if (aContext.IsNull())
13125   {
13126     di << argv[0] << "ERROR : use 'vinit' command before \n";
13127     return 1;
13128   }
13129
13130   if (argc != 3)
13131   {
13132     di << "ERROR : Usage : " << argv[0] << " name angle\n";
13133     return 1;
13134   }
13135
13136   TCollection_AsciiString aName (argv[1]);
13137   Standard_Real anAngle = Draw::Atof (argv[2]);
13138
13139   // find object
13140   ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
13141   Handle(AIS_InteractiveObject) anIObj;
13142   if (!aMap.Find2 (aName, anIObj))
13143   {
13144     di << "Use 'vdisplay' before\n";
13145     return 1;
13146   }
13147
13148   gp_Trsf aTransform;
13149   aTransform.SetRotation (gp_Ax1 (gp_Pnt (0.0, 0.0, 0.0), gp_Vec (1.0, 0.0, 0.0)), anAngle);
13150   aTransform.SetTranslationPart (anIObj->LocalTransformation().TranslationPart());
13151
13152   aContext->SetLocation (anIObj, aTransform);
13153   aContext->UpdateCurrentViewer();
13154   return 0;
13155 }
13156
13157 namespace
13158 {
13159   //! Structure for setting AIS_Manipulator::SetPart() property.
13160   struct ManipAxisModeOnOff
13161   {
13162     Standard_Integer    Axis;
13163     AIS_ManipulatorMode Mode;
13164     Standard_Boolean    ToEnable;
13165
13166     ManipAxisModeOnOff() : Axis (-1), Mode (AIS_MM_None), ToEnable (false) {}
13167   };
13168
13169   enum ManipAjustPosition
13170   {
13171     ManipAjustPosition_Off,
13172     ManipAjustPosition_Center,
13173     ManipAjustPosition_Location,
13174     ManipAjustPosition_ShapeLocation,
13175   };
13176 }
13177
13178 //===============================================================================================
13179 //function : VManipulator
13180 //purpose  :
13181 //===============================================================================================
13182 static int VManipulator (Draw_Interpretor& theDi,
13183                          Standard_Integer  theArgsNb,
13184                          const char**      theArgVec)
13185 {
13186   Handle(V3d_View)   aCurrentView   = ViewerTest::CurrentView();
13187   Handle(V3d_Viewer) aViewer = ViewerTest::GetViewerFromContext();
13188   if (aCurrentView.IsNull()
13189    || aViewer.IsNull())
13190   {
13191     Message::SendFail ("Error: no active viewer");
13192     return 1;
13193   }
13194
13195   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), ViewerTest::CurrentView());
13196   Standard_Integer anArgIter = 1;
13197   Handle(AIS_Manipulator) aManipulator;
13198   ViewerTest_DoubleMapOfInteractiveAndName& aMapAIS = GetMapOfAIS();
13199   TCollection_AsciiString aName;
13200   // parameters
13201   Standard_Integer toAutoActivate = -1, toFollowTranslation = -1, toFollowRotation = -1, toFollowDragging = -1, isZoomable = -1;
13202   Standard_Real aGap = -1.0, aSize = -1.0;
13203   NCollection_Sequence<ManipAxisModeOnOff> aParts;
13204   gp_XYZ aLocation (RealLast(), RealLast(), RealLast()), aVDir, anXDir;
13205   //
13206   bool toDetach = false;
13207   AIS_Manipulator::OptionsForAttach anAttachOptions;
13208   Handle(AIS_InteractiveObject) anAttachObject;
13209   Handle(V3d_View) aViewAffinity;
13210   ManipAjustPosition anAttachPos = ManipAjustPosition_Off;
13211   //
13212   Graphic3d_Vec2i aMousePosFrom(IntegerLast(), IntegerLast());
13213   Graphic3d_Vec2i aMousePosTo  (IntegerLast(), IntegerLast());
13214   Standard_Integer toStopMouseTransform = -1;
13215   // explicit transformation
13216   gp_Trsf aTrsf;
13217   gp_XYZ aTmpXYZ;
13218   Standard_Real aTmpReal = 0.0;
13219   gp_XYZ aRotPnt, aRotAxis;
13220   for (; anArgIter < theArgsNb; ++anArgIter)
13221   {
13222     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13223     anArg.LowerCase();
13224     if (anUpdateTool.parseRedrawMode (anArg))
13225     {
13226       continue;
13227     }
13228     else if (anArg == "-help")
13229     {
13230       theDi.PrintHelp (theArgVec[0]);
13231       return 0;
13232     }
13233     //
13234     else if (anArg == "-autoactivate"
13235           || anArg == "-noautoactivate")
13236     {
13237       toAutoActivate = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13238     }
13239     else if (anArg == "-followtranslation"
13240           || anArg == "-nofollowtranslation")
13241     {
13242       toFollowTranslation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13243     }
13244     else if (anArg == "-followrotation"
13245           || anArg == "-nofollowrotation")
13246     {
13247       toFollowRotation = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13248     }
13249     else if (anArg == "-followdragging"
13250           || anArg == "-nofollowdragging")
13251     {
13252       toFollowDragging = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13253     }
13254     else if (anArg == "-gap"
13255           && anArgIter + 1 < theArgsNb
13256           && Draw::ParseReal (theArgVec[anArgIter + 1], aGap)
13257           && aGap >= 0.0)
13258     {
13259       ++anArgIter;
13260     }
13261     else if (anArg == "-size"
13262           && anArgIter + 1 < theArgsNb
13263           && Draw::ParseReal (theArgVec[anArgIter + 1], aSize)
13264           && aSize > 0.0)
13265     {
13266       ++anArgIter;
13267     }
13268     else if ((anArg == "-part"  && anArgIter + 3 < theArgsNb)
13269           || (anArg == "-parts" && anArgIter + 2 < theArgsNb))
13270     {
13271       ManipAxisModeOnOff aPart;
13272       Standard_Integer aMode = 0;
13273       if (anArg == "-part")
13274       {
13275         if (!Draw::ParseInteger (theArgVec[++anArgIter], aPart.Axis)
13276           || aPart.Axis < 0 || aPart.Axis > 3)
13277         {
13278           Message::SendFail() << "Syntax error: -part axis '" << theArgVec[anArgIter] << "' is out of range [1, 3]";
13279           return 1;
13280         }
13281       }
13282       if (!Draw::ParseInteger (theArgVec[++anArgIter], aMode)
13283         || aMode < 1 || aMode > 4)
13284       {
13285         Message::SendFail() << "Syntax error: -part mode '" << theArgVec[anArgIter] << "' is out of range [1, 4]";
13286         return 1;
13287       }
13288       if (!Draw::ParseOnOff (theArgVec[++anArgIter], aPart.ToEnable))
13289       {
13290         Message::SendFail() << "Syntax error: -part value on/off '" << theArgVec[anArgIter] << "' is incorrect";
13291         return 1;
13292       }
13293       aPart.Mode = static_cast<AIS_ManipulatorMode> (aMode);
13294       aParts.Append (aPart);
13295     }
13296     else if (anArg == "-pos"
13297           && anArgIter + 3 < theArgsNb
13298           && parseXYZ (theArgVec + anArgIter + 1, aLocation))
13299     {
13300       anArgIter += 3;
13301       if (anArgIter + 3 < theArgsNb
13302        && parseXYZ (theArgVec + anArgIter + 1, aVDir)
13303        && aVDir.Modulus() > Precision::Confusion())
13304       {
13305         anArgIter += 3;
13306       }
13307       if (anArgIter + 3 < theArgsNb
13308        && parseXYZ (theArgVec + anArgIter + 1, anXDir)
13309        && anXDir.Modulus() > Precision::Confusion())
13310       {
13311         anArgIter += 3;
13312       }
13313     }
13314     else if (anArg == "-zoomable"
13315           || anArg == "-notzoomable")
13316     {
13317       isZoomable = Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0;
13318     }
13319     //
13320     else if (anArg == "-adjustposition"
13321           || anArg == "-noadjustposition")
13322     {
13323       anAttachPos = ManipAjustPosition_Center;
13324       if (anArgIter + 1 < theArgsNb)
13325       {
13326         TCollection_AsciiString aPosName (theArgVec[++anArgIter]);
13327         aPosName.LowerCase();
13328         if (aPosName == "0")
13329         {
13330           anAttachPos = ManipAjustPosition_Off;
13331         }
13332         else if (aPosName == "1"
13333               || aPosName == "center")
13334         {
13335           anAttachPos = ManipAjustPosition_Center;
13336         }
13337         else if (aPosName == "transformation"
13338               || aPosName == "trsf"
13339               || aPosName == "location"
13340               || aPosName == "loc")
13341         {
13342           anAttachPos = ManipAjustPosition_Location;
13343         }
13344         else if (aPosName == "shapelocation"
13345               || aPosName == "shapeloc")
13346         {
13347           anAttachPos = ManipAjustPosition_ShapeLocation;
13348         }
13349         else
13350         {
13351           --anArgIter;
13352         }
13353       }
13354       anAttachOptions.SetAdjustPosition (anAttachPos == ManipAjustPosition_Center);
13355     }
13356     else if (anArg == "-adjustsize"
13357           || anArg == "-noadjustsize")
13358     {
13359       anAttachOptions.SetAdjustSize (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
13360     }
13361     else if (anArg == "-enablemodes"
13362           || anArg == "-enablemodes")
13363     {
13364       anAttachOptions.SetEnableModes (Draw::ParseOnOffNoIterator (theArgsNb, theArgVec, anArgIter) ? 1 : 0);
13365     }
13366     //
13367     else if (anArg == "-starttransform"
13368           && anArgIter + 2 < theArgsNb
13369           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosFrom.x())
13370           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosFrom.y()))
13371     {
13372       anArgIter += 2;
13373     }
13374     else if (anArg == "-transform"
13375           && anArgIter + 2 < theArgsNb
13376           && Draw::ParseInteger (theArgVec[anArgIter + 1], aMousePosTo.x())
13377           && Draw::ParseInteger (theArgVec[anArgIter + 2], aMousePosTo.y()))
13378     {
13379       anArgIter += 2;
13380     }
13381     else if (anArg == "-stoptransform")
13382     {
13383       toStopMouseTransform = 1;
13384       if (anArgIter + 1 < theArgsNb
13385        && TCollection_AsciiString::IsSameString (theArgVec[anArgIter + 1], "abort", false))
13386       {
13387         ++anArgIter;
13388         toStopMouseTransform = 0;
13389       }
13390     }
13391     //
13392     else if (anArg == "-move"
13393           && anArgIter + 3 < theArgsNb
13394           && parseXYZ (theArgVec + anArgIter + 1, aTmpXYZ))
13395     {
13396       anArgIter += 3;
13397       aTrsf.SetTranslationPart (aTmpXYZ);
13398     }
13399     else if (anArg == "-scale"
13400           && anArgIter + 1 < theArgsNb
13401           && Draw::ParseReal (theArgVec[anArgIter + 1], aTmpReal))
13402     {
13403       ++anArgIter;
13404       aTrsf.SetScale (gp_Pnt(), aTmpReal);
13405     }
13406     else if (anArg == "-rotate"
13407           && anArgIter + 7 < theArgsNb
13408           && parseXYZ (theArgVec + anArgIter + 1, aRotPnt)
13409           && parseXYZ (theArgVec + anArgIter + 4, aRotAxis)
13410           && Draw::ParseReal (theArgVec[anArgIter + 7], aTmpReal))
13411     {
13412       anArgIter += 7;
13413       aTrsf.SetRotation (gp_Ax1 (gp_Pnt (aRotPnt), gp_Dir (aRotAxis)), aTmpReal);
13414     }
13415     //
13416     else if (anArg == "-detach")
13417     {
13418       toDetach = true;
13419     }
13420     else if (anArg == "-attach"
13421           && anArgIter + 1 < theArgsNb)
13422     {
13423       TCollection_AsciiString anObjName (theArgVec[++anArgIter]);
13424       if (!aMapAIS.Find2 (anObjName, anAttachObject))
13425       {
13426         Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' does not exist";
13427         return 1;
13428       }
13429
13430       for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (aMapAIS); anIter.More(); anIter.Next())
13431       {
13432         Handle(AIS_Manipulator) aManip = Handle(AIS_Manipulator)::DownCast (anIter.Key1());
13433         if (!aManip.IsNull()
13434           && aManip->IsAttached()
13435           && aManip->Object() == anAttachObject)
13436         {
13437           Message::SendFail() << "Syntax error: AIS object '" << anObjName << "' already has manipulator";
13438           return 1;
13439         }
13440       }
13441     }
13442     else if (anArg == "-view"
13443           && anArgIter + 1 < theArgsNb
13444           && aViewAffinity.IsNull())
13445     {
13446       TCollection_AsciiString aViewString (theArgVec[++anArgIter]);
13447       if (aViewString == "active")
13448       {
13449         aViewAffinity = ViewerTest::CurrentView();
13450       }
13451       else // Check view name
13452       {
13453         ViewerTest_Names aViewNames (aViewString);
13454         if (!ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
13455         {
13456           Message::SendFail() << "Syntax error: wrong view name '" << aViewString << "'";
13457           return 1;
13458         }
13459         aViewAffinity = ViewerTest_myViews.Find1 (aViewNames.GetViewName());
13460         if (aViewAffinity.IsNull())
13461         {
13462           Message::SendFail() << "Syntax error: cannot find view with name '" << aViewString << "'";
13463           return 1;
13464         }
13465       }
13466     }
13467     else if (aName.IsEmpty())
13468     {
13469       aName = theArgVec[anArgIter];
13470       if (!aMapAIS.IsBound2 (aName))
13471       {
13472         aManipulator = new AIS_Manipulator();
13473         aManipulator->SetModeActivationOnDetection (true);
13474         aMapAIS.Bind (aManipulator, aName);
13475       }
13476       else
13477       {
13478         aManipulator = Handle(AIS_Manipulator)::DownCast (aMapAIS.Find2 (aName));
13479         if (aManipulator.IsNull())
13480         {
13481           Message::SendFail() << "Syntax error: \"" << aName << "\" is not an AIS manipulator";
13482           return 1;
13483         }
13484       }
13485     }
13486     else
13487     {
13488       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
13489     }
13490   }
13491
13492   if (aName.IsEmpty())
13493   {
13494     Message::SendFail ("Syntax error: please specify AIS manipulator's name as the first argument");
13495     return 1;
13496   }
13497   if (!toDetach
13498     && aManipulator.IsNull())
13499   {
13500     aManipulator = new AIS_Manipulator();
13501     aManipulator->SetModeActivationOnDetection (true);
13502     aMapAIS.Bind (aManipulator, aName);
13503   }
13504
13505   // -----------------------------------------
13506   // change properties of manipulator instance
13507   // -----------------------------------------
13508
13509   if (toAutoActivate != -1)
13510   {
13511     aManipulator->SetModeActivationOnDetection (toAutoActivate == 1);
13512   }
13513   if (toFollowTranslation != -1)
13514   {
13515     aManipulator->ChangeTransformBehavior().SetFollowTranslation (toFollowTranslation == 1);
13516   }
13517   if (toFollowRotation != -1)
13518   {
13519     aManipulator->ChangeTransformBehavior().SetFollowRotation (toFollowRotation == 1);
13520   }
13521   if (toFollowDragging != -1)
13522   {
13523     aManipulator->ChangeTransformBehavior().SetFollowDragging (toFollowDragging == 1);
13524   }
13525   if (aGap >= 0.0f)
13526   {
13527     aManipulator->SetGap ((float )aGap);
13528   }
13529
13530   for (NCollection_Sequence<ManipAxisModeOnOff>::Iterator aPartIter (aParts); aPartIter.More(); aPartIter.Next())
13531   {
13532     const ManipAxisModeOnOff& aPart = aPartIter.Value();
13533     if (aPart.Axis == -1)
13534     {
13535       aManipulator->SetPart (aPart.Mode, aPart.ToEnable);
13536     }
13537     else
13538     {
13539       aManipulator->SetPart (aPart.Axis, aPart.Mode, aPart.ToEnable);
13540     }
13541   }
13542
13543   if (aSize > 0.0)
13544   {
13545     aManipulator->SetSize ((float )aSize);
13546   }
13547   if (isZoomable != -1)
13548   {
13549     aManipulator->SetZoomPersistence (isZoomable == 0);
13550
13551     if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
13552     {
13553       ViewerTest::GetAISContext()->Remove  (aManipulator, Standard_False);
13554       ViewerTest::GetAISContext()->Display (aManipulator, Standard_False);
13555     }
13556   }
13557
13558   // ----------------------------------
13559   // detach existing manipulator object
13560   // ----------------------------------
13561
13562   if (toDetach)
13563   {
13564     aManipulator->Detach();
13565     aMapAIS.UnBind2 (aName);
13566     ViewerTest::GetAISContext()->Remove (aManipulator, false);
13567   }
13568
13569   // ---------------------------------------------------
13570   // attach, detach or access manipulator from an object
13571   // ---------------------------------------------------
13572
13573   if (!anAttachObject.IsNull())
13574   {
13575     aManipulator->Attach (anAttachObject, anAttachOptions);
13576   }
13577   if (!aViewAffinity.IsNull())
13578   {
13579     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
13580          anIter.More(); anIter.Next())
13581     {
13582       ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, anIter.Value(), false);
13583     }
13584     ViewerTest::GetAISContext()->SetViewAffinity (aManipulator, aViewAffinity, true);
13585   }
13586
13587   if (anAttachPos != ManipAjustPosition_Off
13588    && aManipulator->IsAttached()
13589    && (anAttachObject.IsNull() || anAttachPos != ManipAjustPosition_Center))
13590   {
13591     gp_Ax2 aPosition = gp::XOY();
13592     const gp_Trsf aBaseTrsf = aManipulator->Object()->LocalTransformation();
13593     switch (anAttachPos)
13594     {
13595       case ManipAjustPosition_Off:
13596       {
13597         break;
13598       }
13599       case ManipAjustPosition_Location:
13600       {
13601         aPosition = gp::XOY().Transformed (aBaseTrsf);
13602         break;
13603       }
13604       case ManipAjustPosition_ShapeLocation:
13605       {
13606         if (Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast (aManipulator->Object()))
13607         {
13608           aPosition = gp::XOY().Transformed (aBaseTrsf * aShapePrs->Shape().Location());
13609         }
13610         else
13611         {
13612           Message::SendFail() << "Syntax error: manipulator is not attached to shape";
13613           return 1;
13614         }
13615         break;
13616       }
13617       case ManipAjustPosition_Center:
13618       {
13619         Bnd_Box aBox;
13620         for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*aManipulator->Objects()); anObjIter.More(); anObjIter.Next())
13621         {
13622           Bnd_Box anObjBox;
13623           anObjIter.Value()->BoundingBox (anObjBox);
13624           aBox.Add (anObjBox);
13625         }
13626         aBox = aBox.FinitePart();
13627         if (!aBox.IsVoid())
13628         {
13629           const gp_Pnt aCenter = (aBox.CornerMin().XYZ() + aBox.CornerMax().XYZ()) * 0.5;
13630           aPosition.SetLocation (aCenter);
13631         }
13632         break;
13633       }
13634     }
13635     aManipulator->SetPosition (aPosition);
13636   }
13637   if (!Precision::IsInfinite (aLocation.X()))
13638   {
13639     if (aVDir.Modulus() <= Precision::Confusion())
13640     {
13641       aVDir = aManipulator->Position().Direction().XYZ();
13642     }
13643     if (anXDir.Modulus() <= Precision::Confusion())
13644     {
13645       anXDir = aManipulator->Position().XDirection().XYZ();
13646     }
13647     aManipulator->SetPosition (gp_Ax2 (gp_Pnt (aLocation), gp_Dir (aVDir), gp_Dir (anXDir)));
13648   }
13649
13650   // --------------------------------------
13651   // apply transformation using manipulator
13652   // --------------------------------------
13653
13654   if (aMousePosFrom.x() != IntegerLast())
13655   {
13656     aManipulator->StartTransform (aMousePosFrom.x(), aMousePosFrom.y(), ViewerTest::CurrentView());
13657   }
13658   if (aMousePosTo.x() != IntegerLast())
13659   {
13660     aManipulator->Transform (aMousePosTo.x(), aMousePosTo.y(), ViewerTest::CurrentView());
13661   }
13662   if (toStopMouseTransform != -1)
13663   {
13664     aManipulator->StopTransform (toStopMouseTransform == 1);
13665   }
13666
13667   if (aTrsf.Form() != gp_Identity)
13668   {
13669     aManipulator->Transform (aTrsf);
13670   }
13671
13672   if (ViewerTest::GetAISContext()->IsDisplayed (aManipulator))
13673   {
13674     ViewerTest::GetAISContext()->Redisplay (aManipulator, true);
13675   }
13676   return 0;
13677 }
13678
13679 //===============================================================================================
13680 //function : VSelectionProperties
13681 //purpose  :
13682 //===============================================================================================
13683 static int VSelectionProperties (Draw_Interpretor& theDi,
13684                                  Standard_Integer  theArgsNb,
13685                                  const char**      theArgVec)
13686 {
13687   const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
13688   if (aCtx.IsNull())
13689   {
13690     Message::SendFail ("Error: no active viewer");
13691     return 1;
13692   }
13693
13694   if (TCollection_AsciiString (theArgVec[0]) == "vhighlightselected")
13695   {
13696     // handle obsolete alias
13697     bool toEnable = true;
13698     if (theArgsNb < 2)
13699     {
13700       theDi << (aCtx->ToHilightSelected() ? "on" : "off");
13701       return 0;
13702     }
13703     else if (theArgsNb != 2
13704          || !Draw::ParseOnOff (theArgVec[1], toEnable))
13705     {
13706       Message::SendFail ("Syntax error: wrong number of parameters");
13707       return 1;
13708     }
13709     if (toEnable != aCtx->ToHilightSelected())
13710     {
13711       aCtx->ClearDetected();
13712       aCtx->SetToHilightSelected (toEnable);
13713     }
13714     return 0;
13715   }
13716
13717   Standard_Boolean toPrint  = theArgsNb == 1;
13718   Standard_Boolean toRedraw = Standard_False;
13719   Standard_Integer anArgIter = 1;
13720   Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
13721   if (anArgIter < theArgsNb)
13722   {
13723     TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
13724     anArgFirst.LowerCase();
13725     ++anArgIter;
13726     if (anArgFirst == "dynhighlight"
13727      || anArgFirst == "dynhilight"
13728      || anArgFirst == "dynamichighlight"
13729      || anArgFirst == "dynamichilight")
13730     {
13731       aType = Prs3d_TypeOfHighlight_Dynamic;
13732     }
13733     else if (anArgFirst == "localdynhighlight"
13734           || anArgFirst == "localdynhilight"
13735           || anArgFirst == "localdynamichighlight"
13736           || anArgFirst == "localdynamichilight")
13737     {
13738       aType = Prs3d_TypeOfHighlight_LocalDynamic;
13739     }
13740     else if (anArgFirst == "selhighlight"
13741           || anArgFirst == "selhilight"
13742           || anArgFirst == "selectedhighlight"
13743           || anArgFirst == "selectedhilight")
13744     {
13745       aType = Prs3d_TypeOfHighlight_Selected;
13746     }
13747     else if (anArgFirst == "localselhighlight"
13748           || anArgFirst == "localselhilight"
13749           || anArgFirst == "localselectedhighlight"
13750           || anArgFirst == "localselectedhilight")
13751     {
13752       aType = Prs3d_TypeOfHighlight_LocalSelected;
13753     }
13754     else
13755     {
13756       --anArgIter;
13757     }
13758   }
13759   for (; anArgIter < theArgsNb; ++anArgIter)
13760   {
13761     TCollection_AsciiString anArg (theArgVec[anArgIter]);
13762     anArg.LowerCase();
13763     if (anArg == "-help")
13764     {
13765       theDi.PrintHelp (theArgVec[0]);
13766       return 0;
13767     }
13768     else if (anArg == "-print")
13769     {
13770       toPrint = Standard_True;
13771     }
13772     else if (anArg == "-autoactivate")
13773     {
13774       Standard_Boolean toEnable = Standard_True;
13775       if (anArgIter + 1 < theArgsNb
13776        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13777       {
13778         ++anArgIter;
13779       }
13780       aCtx->SetAutoActivateSelection (toEnable);
13781     }
13782     else if (anArg == "-automatichighlight"
13783           || anArg == "-automatichilight"
13784           || anArg == "-autohighlight"
13785           || anArg == "-autohilight")
13786     {
13787       Standard_Boolean toEnable = Standard_True;
13788       if (anArgIter + 1 < theArgsNb
13789        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13790       {
13791         ++anArgIter;
13792       }
13793       aCtx->ClearSelected (false);
13794       aCtx->ClearDetected();
13795       aCtx->SetAutomaticHilight (toEnable);
13796       toRedraw = true;
13797     }
13798     else if (anArg == "-highlightselected"
13799           || anArg == "-hilightselected")
13800     {
13801       Standard_Boolean toEnable = Standard_True;
13802       if (anArgIter + 1 < theArgsNb
13803        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
13804       {
13805         ++anArgIter;
13806       }
13807       aCtx->ClearDetected();
13808       aCtx->SetToHilightSelected (toEnable);
13809       toRedraw = true;
13810     }
13811     else if (anArg == "-pickstrategy"
13812           || anArg == "-pickingstrategy")
13813     {
13814       if (++anArgIter >= theArgsNb)
13815       {
13816         Message::SendFail ("Syntax error: type of highlighting is undefined");
13817         return 1;
13818       }
13819
13820       SelectMgr_PickingStrategy aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13821       TCollection_AsciiString aVal (theArgVec[anArgIter]);
13822       aVal.LowerCase();
13823       if (aVal == "first"
13824        || aVal == "firstaccepted"
13825        || aVal == "firstacceptable")
13826       {
13827         aStrategy = SelectMgr_PickingStrategy_FirstAcceptable;
13828       }
13829       else if (aVal == "topmost"
13830             || aVal == "onlyTopmost")
13831       {
13832         aStrategy = SelectMgr_PickingStrategy_OnlyTopmost;
13833       }
13834       else
13835       {
13836         Message::SendFail() << "Syntax error: unknown picking strategy '" << aVal << "'";
13837         return 1;
13838       }
13839
13840       aCtx->SetPickingStrategy (aStrategy);
13841     }
13842     else if (anArg == "-pixtol"
13843           && anArgIter + 1 < theArgsNb)
13844     {
13845       aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
13846     }
13847     else if (anArg == "-preferclosest")
13848     {
13849       bool toPreferClosest = true;
13850       if (anArgIter + 1 < theArgsNb
13851        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toPreferClosest))
13852       {
13853         ++anArgIter;
13854       }
13855       aCtx->MainSelector()->SetPickClosest (toPreferClosest);
13856     }
13857     else if ((anArg == "-depthtol"
13858            || anArg == "-depthtolerance")
13859           && anArgIter + 1 < theArgsNb)
13860     {
13861       TCollection_AsciiString aTolType (theArgVec[++anArgIter]);
13862       aTolType.LowerCase();
13863       if (aTolType == "uniform")
13864       {
13865         if (anArgIter + 1 >= theArgsNb)
13866         {
13867           Message::SendFail() << "Syntax error: wrong number of arguments";
13868           return 1;
13869         }
13870         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_Uniform,
13871                                                  Draw::Atof (theArgVec[++anArgIter]));
13872       }
13873       else if (aTolType == "uniformpx")
13874       {
13875         if (anArgIter + 1 >= theArgsNb)
13876         {
13877           Message::SendFail() << "Syntax error: wrong number of arguments";
13878           return 1;
13879         }
13880         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_UniformPixels,
13881                                                  Draw::Atof (theArgVec[++anArgIter]));
13882       }
13883       else if (aTolType == "sensfactor")
13884       {
13885         aCtx->MainSelector()->SetDepthTolerance (SelectMgr_TypeOfDepthTolerance_SensitivityFactor, 0.0);
13886       }
13887       else
13888       {
13889         Message::SendFail() << "Syntax error at '" << aTolType << "'";
13890         return 1;
13891       }
13892     }
13893     else if ((anArg == "-mode"
13894            || anArg == "-dispmode")
13895           && anArgIter + 1 < theArgsNb)
13896     {
13897       if (aType == Prs3d_TypeOfHighlight_None)
13898       {
13899         Message::SendFail ("Syntax error: type of highlighting is undefined");
13900         return 1;
13901       }
13902
13903       const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
13904       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13905       aStyle->SetDisplayMode (aDispMode);
13906       toRedraw = Standard_True;
13907     }
13908     else if (anArg == "-layer"
13909           && anArgIter + 1 < theArgsNb)
13910     {
13911       if (aType == Prs3d_TypeOfHighlight_None)
13912       {
13913         Message::SendFail ("Syntax error: type of highlighting is undefined");
13914         return 1;
13915       }
13916
13917       ++anArgIter;
13918       Graphic3d_ZLayerId aNewLayer = Graphic3d_ZLayerId_UNKNOWN;
13919       if (!ViewerTest::ParseZLayer (theArgVec[anArgIter], aNewLayer))
13920       {
13921         Message::SendFail() << "Syntax error at " << theArgVec[anArgIter];
13922         return 1;
13923       }
13924
13925       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13926       aStyle->SetZLayer (aNewLayer);
13927       toRedraw = Standard_True;
13928     }
13929     else if (anArg == "-hicolor"
13930           || anArg == "-selcolor"
13931           || anArg == "-color")
13932     {
13933       if (anArg.StartsWith ("-hi"))
13934       {
13935         aType = Prs3d_TypeOfHighlight_Dynamic;
13936       }
13937       else if (anArg.StartsWith ("-sel"))
13938       {
13939         aType = Prs3d_TypeOfHighlight_Selected;
13940       }
13941       else if (aType == Prs3d_TypeOfHighlight_None)
13942       {
13943         Message::SendFail ("Syntax error: type of highlighting is undefined");
13944         return 1;
13945       }
13946
13947       Quantity_Color aColor;
13948       Standard_Integer aNbParsed = Draw::ParseColor (theArgsNb - anArgIter - 1,
13949                                                      theArgVec + anArgIter + 1,
13950                                                      aColor);
13951       if (aNbParsed == 0)
13952       {
13953         Message::SendFail ("Syntax error: need more arguments");
13954         return 1;
13955       }
13956       anArgIter += aNbParsed;
13957
13958       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13959       aStyle->SetColor (aColor);
13960       toRedraw = Standard_True;
13961     }
13962     else if ((anArg == "-transp"
13963            || anArg == "-transparency"
13964            || anArg == "-hitransp"
13965            || anArg == "-seltransp"
13966            || anArg == "-hitransplocal"
13967            || anArg == "-seltransplocal")
13968           && anArgIter + 1 < theArgsNb)
13969     {
13970       if (anArg.StartsWith ("-hi"))
13971       {
13972         aType = Prs3d_TypeOfHighlight_Dynamic;
13973       }
13974       else if (anArg.StartsWith ("-sel"))
13975       {
13976         aType = Prs3d_TypeOfHighlight_Selected;
13977       }
13978       else if (aType == Prs3d_TypeOfHighlight_None)
13979       {
13980         Message::SendFail ("Syntax error: type of highlighting is undefined");
13981         return 1;
13982       }
13983
13984       const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
13985       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
13986       aStyle->SetTransparency ((Standard_ShortReal )aTransp);
13987       toRedraw = Standard_True;
13988     }
13989     else if ((anArg == "-mat"
13990            || anArg == "-material")
13991           && anArgIter + 1 < theArgsNb)
13992     {
13993       if (aType == Prs3d_TypeOfHighlight_None)
13994       {
13995         Message::SendFail ("Syntax error: type of highlighting is undefined");
13996         return 1;
13997       }
13998
13999       const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
14000       Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
14001       if (aMatName != Graphic3d_NameOfMaterial_DEFAULT)
14002       {
14003         ++anArgIter;
14004         Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
14005         *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
14006         Graphic3d_MaterialAspect aMat (aMatName);
14007         aMat.SetColor (aStyle->Color());
14008         aMat.SetTransparency (aStyle->Transparency());
14009         anAspect->SetFrontMaterial (aMat);
14010         anAspect->SetInteriorColor (aStyle->Color());
14011         aStyle->SetBasicFillAreaAspect (anAspect);
14012       }
14013       else
14014       {
14015         aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
14016       }
14017       toRedraw = Standard_True;
14018     }
14019     else
14020     {
14021       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
14022       return 1;
14023     }
14024   }
14025
14026   if (toPrint)
14027   {
14028     const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
14029     const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
14030     theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
14031     theDi << "Auto-highlight                 : " << (aCtx->AutomaticHilight() ? "On" : "Off") << "\n";
14032     theDi << "Highlight selected             : " << (aCtx->ToHilightSelected() ? "On" : "Off") << "\n";
14033     theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
14034     theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
14035     theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
14036     theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
14037     theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
14038     theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
14039     theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
14040     theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
14041     theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
14042   }
14043
14044   if (aCtx->NbSelected() != 0 && toRedraw)
14045   {
14046     aCtx->HilightSelected (Standard_True);
14047   }
14048
14049   return 0;
14050 }
14051
14052 //===============================================================================================
14053 //function : VDumpSelectionImage
14054 //purpose  :
14055 //===============================================================================================
14056 static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
14057                                 Standard_Integer  theArgsNb,
14058                                 const char**      theArgVec)
14059 {
14060   if (theArgsNb < 2)
14061   {
14062     Message::SendFail() << "Syntax error: wrong number arguments for '" << theArgVec[0] << "'";
14063     return 1;
14064   }
14065
14066   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
14067   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
14068   if (aContext.IsNull())
14069   {
14070     Message::SendFail ("Error: no active viewer");
14071     return 1;
14072   }
14073
14074   TCollection_AsciiString aFile;
14075   StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
14076   Handle(Graphic3d_Camera) aCustomCam;
14077   Image_Format anImgFormat = Image_Format_BGR;
14078   Standard_Integer aPickedIndex = 1;
14079   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
14080   {
14081     TCollection_AsciiString aParam (theArgVec[anArgIter]);
14082     aParam.LowerCase();
14083     if (aParam == "-type")
14084     {
14085       if (++anArgIter >= theArgsNb)
14086       {
14087         Message::SendFail ("Syntax error: wrong number parameters of flag '-depth'");
14088         return 1;
14089       }
14090
14091       TCollection_AsciiString aValue (theArgVec[anArgIter]);
14092       aValue.LowerCase();
14093       if (aValue == "depth"
14094        || aValue == "normdepth"
14095        || aValue == "normalizeddepth")
14096       {
14097         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
14098         anImgFormat = Image_Format_GrayF;
14099       }
14100       if (aValue == "depthinverted"
14101        || aValue == "normdepthinverted"
14102        || aValue == "normalizeddepthinverted"
14103        || aValue == "inverted")
14104       {
14105         aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
14106         anImgFormat = Image_Format_GrayF;
14107       }
14108       else if (aValue == "unnormdepth"
14109             || aValue == "unnormalizeddepth")
14110       {
14111         aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
14112         anImgFormat = Image_Format_GrayF;
14113       }
14114       else if (aValue == "objectcolor"
14115             || aValue == "object"
14116             || aValue == "color")
14117       {
14118         aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
14119       }
14120       else if (aValue == "entitycolor"
14121             || aValue == "entity")
14122       {
14123         aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
14124       }
14125       else if (aValue == "ownercolor"
14126             || aValue == "owner")
14127       {
14128         aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
14129       }
14130       else if (aValue == "selectionmodecolor"
14131             || aValue == "selectionmode"
14132             || aValue == "selmodecolor"
14133             || aValue == "selmode")
14134       {
14135         aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
14136       }
14137     }
14138     else if (aParam == "-picked"
14139           || aParam == "-pickeddepth"
14140           || aParam == "-pickedindex")
14141     {
14142       if (++anArgIter >= theArgsNb)
14143       {
14144         Message::SendFail() << "Syntax error: wrong number parameters at '" << aParam << "'";
14145         return 1;
14146       }
14147
14148       aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
14149     }
14150     else if (anArgIter + 1 < theArgsNb
14151           && aParam == "-xrpose")
14152     {
14153       TCollection_AsciiString anXRArg (theArgVec[++anArgIter]);
14154       anXRArg.LowerCase();
14155       if (anXRArg == "base")
14156       {
14157         aCustomCam = aView->View()->BaseXRCamera();
14158       }
14159       else if (anXRArg == "head")
14160       {
14161         aCustomCam = aView->View()->PosedXRCamera();
14162       }
14163       else
14164       {
14165         Message::SendFail() << "Syntax error: unknown XR pose '" << anXRArg << "'";
14166         return 1;
14167       }
14168       if (aCustomCam.IsNull())
14169       {
14170         Message::SendFail() << "Error: undefined XR pose";
14171         return 0;
14172       }
14173     }
14174     else if (aFile.IsEmpty())
14175     {
14176       aFile = theArgVec[anArgIter];
14177     }
14178     else
14179     {
14180       Message::SendFail() << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
14181       return 1;
14182     }
14183   }
14184   if (aFile.IsEmpty())
14185   {
14186     Message::SendFail ("Syntax error: image file name is missing");
14187     return 1;
14188   }
14189
14190   Standard_Integer aWidth = 0, aHeight = 0;
14191   aView->Window()->Size (aWidth, aHeight);
14192
14193   Image_AlienPixMap aPixMap;
14194   if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
14195   {
14196     Message::SendFail ("Error: can't allocate image");
14197     return 1;
14198   }
14199
14200   const bool wasImmUpdate = aView->SetImmediateUpdate (false);
14201   Handle(Graphic3d_Camera) aCamBack = aView->Camera();
14202   if (!aCustomCam.IsNull())
14203   {
14204     aView->SetCamera (aCustomCam);
14205   }
14206   if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
14207   {
14208     Message::SendFail ("Error: can't generate selection image");
14209     return 1;
14210   }
14211   if (!aCustomCam.IsNull())
14212   {
14213     aView->SetCamera (aCamBack);
14214   }
14215   aView->SetImmediateUpdate (wasImmUpdate);
14216
14217   if (!aPixMap.Save (aFile))
14218   {
14219     Message::SendFail ("Error: can't save selection image");
14220     return 0;
14221   }
14222   return 0;
14223 }
14224
14225 //===============================================================================================
14226 //function : VViewCube
14227 //purpose  :
14228 //===============================================================================================
14229 static int VViewCube (Draw_Interpretor& ,
14230                       Standard_Integer  theNbArgs,
14231                       const char**      theArgVec)
14232 {
14233   const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
14234   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
14235   if (aContext.IsNull() || aView.IsNull())
14236   {
14237     Message::SendFail ("Error: no active viewer");
14238     return 1;
14239   }
14240   else if (theNbArgs < 2)
14241   {
14242     Message::SendFail ("Syntax error: wrong number arguments");
14243     return 1;
14244   }
14245
14246   Handle(AIS_ViewCube) aViewCube;
14247   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
14248   Quantity_Color aColorRgb;
14249   TCollection_AsciiString aName;
14250   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
14251   {
14252     TCollection_AsciiString anArg (theArgVec[anArgIter]);
14253     anArg.LowerCase();
14254     if (anUpdateTool.parseRedrawMode (anArg))
14255     {
14256       //
14257     }
14258     else if (aViewCube.IsNull())
14259     {
14260       aName = theArgVec[anArgIter];
14261       if (aName.StartsWith ("-"))
14262       {
14263         Message::SendFail ("Syntax error: object name should be specified");
14264         return 1;
14265       }
14266       Handle(AIS_InteractiveObject) aPrs;
14267       GetMapOfAIS().Find2 (aName, aPrs);
14268       aViewCube = Handle(AIS_ViewCube)::DownCast (aPrs);
14269       if (aViewCube.IsNull())
14270       {
14271         aViewCube = new AIS_ViewCube();
14272         aViewCube->SetBoxColor (Quantity_NOC_GRAY50);
14273         aViewCube->SetViewAnimation (ViewerTest::CurrentEventManager()->ViewAnimation());
14274         aViewCube->SetFixedAnimationLoop (false);
14275       }
14276     }
14277     else if (anArg == "-reset")
14278     {
14279       aViewCube->ResetStyles();
14280     }
14281     else if (anArg == "-color"
14282           || anArg == "-boxcolor"
14283           || anArg == "-boxsidecolor"
14284           || anArg == "-sidecolor"
14285           || anArg == "-boxedgecolor"
14286           || anArg == "-edgecolor"
14287           || anArg == "-boxcornercolor"
14288           || anArg == "-cornercolor"
14289           || anArg == "-innercolor"
14290           || anArg == "-textcolor"
14291           || anArg == "-xaxistextcolor"
14292           || anArg == "-yaxistextcolor"
14293           || anArg == "-zaxistextcolor")
14294     {
14295       Standard_Integer aNbParsed = Draw::ParseColor (theNbArgs - anArgIter - 1,
14296                                                      theArgVec + anArgIter + 1,
14297                                                      aColorRgb);
14298       if (aNbParsed == 0)
14299       {
14300         Message::SendFail() << "Syntax error at '" << anArg << "'";
14301         return 1;
14302       }
14303       anArgIter += aNbParsed;
14304       if (anArg == "-boxcolor")
14305       {
14306         aViewCube->SetBoxColor (aColorRgb);
14307       }
14308       else if (anArg == "-boxsidecolor"
14309             || anArg == "-sidecolor")
14310       {
14311         aViewCube->BoxSideStyle()->SetColor (aColorRgb);
14312         aViewCube->SynchronizeAspects();
14313       }
14314       else if (anArg == "-boxedgecolor"
14315             || anArg == "-edgecolor")
14316       {
14317         aViewCube->BoxEdgeStyle()->SetColor (aColorRgb);
14318         aViewCube->SynchronizeAspects();
14319       }
14320       else if (anArg == "-boxcornercolor"
14321             || anArg == "-cornercolor")
14322       {
14323         aViewCube->BoxCornerStyle()->SetColor (aColorRgb);
14324         aViewCube->SynchronizeAspects();
14325       }
14326       else if (anArg == "-innercolor")
14327       {
14328         aViewCube->SetInnerColor (aColorRgb);
14329       }
14330       else if (anArg == "-textcolor")
14331       {
14332         aViewCube->SetTextColor (aColorRgb);
14333       }
14334       else if (anArg == "-xaxistextcolor"
14335             || anArg == "-yaxistextcolor"
14336             || anArg == "-zaxistextcolor")
14337       {
14338         Prs3d_DatumParts aDatum = anArg.Value (2) == 'x'
14339                                 ? Prs3d_DatumParts_XAxis
14340                                 : (anArg.Value (2) == 'y'
14341                                  ? Prs3d_DatumParts_YAxis
14342                                  : Prs3d_DatumParts_ZAxis);
14343         aViewCube->Attributes()->SetOwnDatumAspects();
14344         aViewCube->Attributes()->DatumAspect()->TextAspect (aDatum)->SetColor (aColorRgb);
14345       }
14346       else
14347       {
14348         aViewCube->SetColor (aColorRgb);
14349       }
14350     }
14351     else if (anArgIter + 1 < theNbArgs
14352           && (anArg == "-transparency"
14353            || anArg == "-boxtransparency"))
14354     {
14355       const Standard_Real aValue = Draw::Atof (theArgVec[++anArgIter]);
14356       if (aValue < 0.0 || aValue > 1.0)
14357       {
14358         Message::SendFail() << "Syntax error: invalid transparency value " << theArgVec[anArgIter];
14359         return 1;
14360       }
14361
14362       if (anArg == "-boxtransparency")
14363       {
14364         aViewCube->SetBoxTransparency (aValue);
14365       }
14366       else
14367       {
14368         aViewCube->SetTransparency (aValue);
14369       }
14370     }
14371     else if (anArg == "-axes"
14372           || anArg == "-edges"
14373           || anArg == "-vertices"
14374           || anArg == "-vertexes"
14375           || anArg == "-fixedanimation")
14376     {
14377       bool toShow = true;
14378       if (anArgIter + 1 < theNbArgs
14379        && Draw::ParseOnOff (theArgVec[anArgIter + 1], toShow))
14380       {
14381         ++anArgIter;
14382       }
14383       if (anArg == "-fixedanimation")
14384       {
14385         aViewCube->SetFixedAnimationLoop (toShow);
14386       }
14387       else if (anArg == "-axes")
14388       {
14389         aViewCube->SetDrawAxes (toShow);
14390       }
14391       else if (anArg == "-edges")
14392       {
14393         aViewCube->SetDrawEdges (toShow);
14394       }
14395       else
14396       {
14397         aViewCube->SetDrawVertices (toShow);
14398       }
14399     }
14400     else if (anArg == "-yup"
14401           || anArg == "-zup")
14402     {
14403       bool isOn = true;
14404       if (anArgIter + 1 < theNbArgs
14405        && Draw::ParseOnOff (theArgVec[anArgIter + 1], isOn))
14406       {
14407         ++anArgIter;
14408       }
14409       if (anArg == "-yup")
14410       {
14411         aViewCube->SetYup (isOn);
14412       }
14413       else
14414       {
14415         aViewCube->SetYup (!isOn);
14416       }
14417     }
14418     else if (anArgIter + 1 < theNbArgs
14419           && anArg == "-font")
14420     {
14421       aViewCube->SetFont (theArgVec[++anArgIter]);
14422     }
14423     else if (anArgIter + 1 < theNbArgs
14424           && anArg == "-fontheight")
14425     {
14426       aViewCube->SetFontHeight (Draw::Atof (theArgVec[++anArgIter]));
14427     }
14428     else if (anArgIter + 1 < theNbArgs
14429           && (anArg == "-size"
14430            || anArg == "-boxsize"))
14431     {
14432       aViewCube->SetSize (Draw::Atof (theArgVec[++anArgIter]),
14433                           anArg != "-boxsize");
14434     }
14435     else if (anArgIter + 1 < theNbArgs
14436           && (anArg == "-boxfacet"
14437            || anArg == "-boxfacetextension"
14438            || anArg == "-facetextension"
14439            || anArg == "-extension"))
14440     {
14441       aViewCube->SetBoxFacetExtension (Draw::Atof (theArgVec[++anArgIter]));
14442     }
14443     else if (anArgIter + 1 < theNbArgs
14444           && (anArg == "-boxedgegap"
14445            || anArg == "-edgegap"))
14446     {
14447       aViewCube->SetBoxEdgeGap (Draw::Atof (theArgVec[++anArgIter]));
14448     }
14449     else if (anArgIter + 1 < theNbArgs
14450           && (anArg == "-boxedgeminsize"
14451            || anArg == "-edgeminsize"))
14452     {
14453       aViewCube->SetBoxEdgeMinSize (Draw::Atof (theArgVec[++anArgIter]));
14454     }
14455     else if (anArgIter + 1 < theNbArgs
14456           && (anArg == "-boxcornerminsize"
14457            || anArg == "-cornerminsize"))
14458     {
14459       aViewCube->SetBoxCornerMinSize (Draw::Atof (theArgVec[++anArgIter]));
14460     }
14461     else if (anArgIter + 1 < theNbArgs
14462           && anArg == "-axespadding")
14463     {
14464       aViewCube->SetAxesPadding (Draw::Atof (theArgVec[++anArgIter]));
14465     }
14466     else if (anArgIter + 1 < theNbArgs
14467           && anArg == "-roundradius")
14468     {
14469       aViewCube->SetRoundRadius (Draw::Atof (theArgVec[++anArgIter]));
14470     }
14471     else if (anArgIter + 1 < theNbArgs
14472           && anArg == "-duration")
14473     {
14474       aViewCube->SetDuration (Draw::Atof (theArgVec[++anArgIter]));
14475     }
14476     else if (anArgIter + 1 < theNbArgs
14477           && anArg == "-axesradius")
14478     {
14479       aViewCube->SetAxesRadius (Draw::Atof (theArgVec[++anArgIter]));
14480     }
14481     else if (anArgIter + 1 < theNbArgs
14482           && anArg == "-axesconeradius")
14483     {
14484       aViewCube->SetAxesConeRadius (Draw::Atof (theArgVec[++anArgIter]));
14485     }
14486     else if (anArgIter + 1 < theNbArgs
14487           && anArg == "-axessphereradius")
14488     {
14489       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
14490     }
14491     else
14492     {
14493       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14494       return 1;
14495     }
14496   }
14497   if (aViewCube.IsNull())
14498   {
14499     Message::SendFail ("Syntax error: wrong number of arguments");
14500     return 1;
14501   }
14502
14503   ViewerTest::Display (aName, aViewCube, false);
14504   return 0;
14505 }
14506
14507 //===============================================================================================
14508 //function : VColorConvert
14509 //purpose  :
14510 //===============================================================================================
14511 static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
14512 {
14513   if (theNbArgs != 6)
14514   {
14515     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
14516     return 1;
14517   }
14518
14519   Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
14520   if (! convertFrom && strcasecmp (theArgVec[1], "to"))
14521   {
14522     std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
14523     return 1;
14524   }
14525
14526   const char* aTypeStr = theArgVec[2];
14527   Quantity_TypeOfColor aType = Quantity_TOC_RGB;
14528   if (! strcasecmp (aTypeStr, "srgb"))
14529   {
14530     aType = Quantity_TOC_sRGB;
14531   }
14532   else if (! strcasecmp (aTypeStr, "hls"))
14533   {
14534     aType = Quantity_TOC_HLS;
14535   }
14536   else if (! strcasecmp (aTypeStr, "lab"))
14537   {
14538     aType = Quantity_TOC_CIELab;
14539   }
14540   else if (! strcasecmp (aTypeStr, "lch"))
14541   {
14542     aType = Quantity_TOC_CIELch;
14543   }
14544   else
14545   {
14546     std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
14547     return 1;
14548   }
14549
14550   double aC1 = Draw::Atof (theArgVec[3]);
14551   double aC2 = Draw::Atof (theArgVec[4]);
14552   double aC3 = Draw::Atof (theArgVec[5]);
14553
14554   Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
14555   aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
14556
14557   // print values with 6 decimal digits
14558   char buffer[1024];
14559   Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
14560   theDI << buffer;
14561
14562   return 0;
14563 }
14564  
14565 //===============================================================================================
14566 //function : VColorDiff
14567 //purpose  :
14568 //===============================================================================================
14569 static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer  theNbArgs, const char** theArgVec)
14570 {
14571   if (theNbArgs != 7)
14572   {
14573     std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
14574     return 1;
14575   }
14576
14577   double aR1 = Draw::Atof (theArgVec[1]);
14578   double aG1 = Draw::Atof (theArgVec[2]);
14579   double aB1 = Draw::Atof (theArgVec[3]);
14580   double aR2 = Draw::Atof (theArgVec[4]);
14581   double aG2 = Draw::Atof (theArgVec[5]);
14582   double aB2 = Draw::Atof (theArgVec[6]);
14583
14584   Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
14585   Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
14586
14587   theDI << aColor1.DeltaE2000 (aColor2);
14588
14589   return 0;
14590 }
14591  
14592 //===============================================================================================
14593 //function : VSelBvhBuild
14594 //purpose  :
14595 //===============================================================================================
14596 static int VSelBvhBuild (Draw_Interpretor& /*theDI*/, Standard_Integer theNbArgs, const char** theArgVec)
14597 {
14598   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
14599   if (aCtx.IsNull())
14600   {
14601     Message::SendFail ("Error: no active viewer");
14602     return 1;
14603   }
14604
14605   if (theNbArgs < 2)
14606   {
14607     Message::SendFail ("Error: command syntax is incorrect, see help");
14608     return 1;
14609   }
14610
14611   Standard_Integer toEnable = -1;
14612   Standard_Integer aThreadsNb = -1;
14613   Standard_Boolean toWait = Standard_False;
14614
14615   for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
14616   {
14617     TCollection_AsciiString anArg (theArgVec[anArgIter]);
14618     anArg.LowerCase();
14619
14620     if (anArg == "-nbthreads"
14621         && anArgIter + 1 < theNbArgs)
14622     {
14623       aThreadsNb = Draw::Atoi (theArgVec[++anArgIter]);
14624       if (aThreadsNb < 1)
14625       {
14626         aThreadsNb = Max (1, OSD_Parallel::NbLogicalProcessors() - 1);
14627       }
14628     }
14629     else if (anArg == "-wait")
14630     {
14631       toWait = Standard_True;
14632     }
14633     else if (toEnable == -1)
14634     {
14635       Standard_Boolean toEnableValue = Standard_True;
14636       if (Draw::ParseOnOff (anArg.ToCString(), toEnableValue))
14637       {
14638         toEnable = toEnableValue ? 1 : 0;
14639       }
14640       else
14641       {
14642         Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14643         return 1;
14644       }
14645     }
14646     else
14647     {
14648       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
14649       return 1;
14650     }
14651   }
14652
14653   if (aThreadsNb == -1)
14654   {
14655     aThreadsNb = 1;
14656   }
14657   if (toEnable != -1)
14658   {
14659     aCtx->MainSelector()->SetToPrebuildBVH (toEnable == 1, aThreadsNb);
14660   }
14661   if (toWait)
14662   {
14663     aCtx->MainSelector()->WaitForBVHBuild();
14664   }
14665
14666   return 0;
14667 }
14668
14669 //=======================================================================
14670 //function : ViewerCommands
14671 //purpose  :
14672 //=======================================================================
14673
14674 void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
14675 {
14676
14677   const char *group = "ZeViewer";
14678   theCommands.Add("vinit",
14679           "vinit [-name viewName] [-left leftPx] [-top topPx] [-width widthPx] [-height heightPx]"
14680     "\n\t\t:     [-exitOnClose] [-closeOnEscape] [-cloneActive] [-2d_mode {on|off}=off]"
14681   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
14682     "\n\t\t:     [-display displayName]"
14683   #endif
14684     "\n\t\t: Creates new View window with specified name viewName."
14685     "\n\t\t: By default the new view is created in the viewer and in"
14686     "\n\t\t: graphic driver shared with active view."
14687     "\n\t\t:  -name {driverName/viewerName/viewName | viewerName/viewName | viewName}"
14688     "\n\t\t: If driverName isn't specified the driver will be shared with active view."
14689     "\n\t\t: If viewerName isn't specified the viewer will be shared with active view."
14690 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
14691     "\n\t\t:  -display HostName.DisplayNumber[:ScreenNumber]"
14692     "\n\t\t: Display name will be used within creation of graphic driver, when specified."
14693 #endif
14694     "\n\t\t:  -left,  -top    pixel position of left top corner of the window."
14695     "\n\t\t:  -width, -height width and height of window respectively."
14696     "\n\t\t:  -cloneActive floag to copy camera and dimensions of active view."
14697     "\n\t\t:  -exitOnClose when specified, closing the view will exit application."
14698     "\n\t\t:  -closeOnEscape when specified, view will be closed on pressing Escape."
14699     "\n\t\t:  -2d_mode when on, view will not react on rotate scene events"
14700     "\n\t\t: Additional commands for operations with views: vclose, vactivate, vviewlist.",
14701     __FILE__,VInit,group);
14702   theCommands.Add("vclose" ,
14703     "[view_id [keep_context=0|1]]\n"
14704     "or vclose ALL - to remove all created views\n"
14705     " - removes view(viewer window) defined by its view_id.\n"
14706     " - keep_context: by default 0; if 1 and the last view is deleted"
14707     " the current context is not removed.",
14708     __FILE__,VClose,group);
14709   theCommands.Add("vactivate" ,
14710     "vactivate view_id [-noUpdate]"
14711     " - activates view(viewer window) defined by its view_id",
14712     __FILE__,VActivate,group);
14713   theCommands.Add("vviewlist",
14714     "vviewlist [format={tree, long}]"
14715     " - prints current list of views per viewer and graphic_driver ID shared between viewers"
14716     " - format: format of result output, if tree the output is a tree view;"
14717     "otherwise it's a list of full view names. By default format = tree",
14718     __FILE__,VViewList,group);
14719   theCommands.Add("vhelp" ,
14720     "vhelp            : display help on the viewer commands",
14721     __FILE__,VHelp,group);
14722   theCommands.Add("vviewproj",
14723           "vviewproj [top|bottom|left|right|front|back|axoLeft|axoRight]"
14724     "\n\t\t:         [+-X+-Y+-Z] [-Zup|-Yup] [-frame +-X+-Y]"
14725     "\n\t\t: Setup view direction"
14726     "\n\t\t:   -Yup      use Y-up convention instead of Zup (which is default)."
14727     "\n\t\t:   +-X+-Y+-Z define direction as combination of DX, DY and DZ;"
14728     "\n\t\t:             for example '+Z' will show front of the model,"
14729     "\n\t\t:             '-X-Y+Z' will define left axonometrical view."
14730     "\n\t\t:   -frame    define camera Up and Right directions (regardless Up convention);"
14731     "\n\t\t:             for example '+X+Z' will show front of the model with Z-up."
14732     __FILE__,VViewProj,group);
14733   theCommands.Add("vtop" ,
14734     "vtop or <T>      : Top view. Orientation +X+Y" ,
14735     __FILE__,VViewProj,group);
14736   theCommands.Add("vbottom" ,
14737     "vbottom          : Bottom view. Orientation +X-Y" ,
14738     __FILE__,VViewProj,group);
14739   theCommands.Add("vleft" ,
14740     "vleft            : Left view. Orientation -Y+Z" ,
14741     __FILE__,VViewProj,group);
14742   theCommands.Add("vright" ,
14743     "vright           : Right view. Orientation +Y+Z" ,
14744     __FILE__,VViewProj,group);
14745   theCommands.Add("vaxo" ,
14746     " vaxo or <A>     : Axonometric view. Orientation +X-Y+Z",
14747     __FILE__,VViewProj,group);
14748   theCommands.Add("vfront" ,
14749     "vfront           : Front view. Orientation +X+Z" ,
14750     __FILE__,VViewProj,group);
14751   theCommands.Add("vback" ,
14752     "vback            : Back view. Orientation -X+Z" ,
14753     __FILE__,VViewProj,group);
14754   theCommands.Add("vpick" ,
14755     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
14756     VPick,group);
14757   theCommands.Add("vfit",
14758     "vfit or <F> [-selected] [-noupdate]"
14759     "\n\t\t: [-selected] fits the scene according to bounding box of currently selected objects",
14760     __FILE__,VFit,group);
14761   theCommands.Add ("vfitarea",
14762     "vfitarea x1 y1 x2 y2"
14763     "\n\t\t: vfitarea x1 y1 z1 x2 y2 z2"
14764     "\n\t\t: Fit view to show area located between two points"
14765     "\n\t\t: given in world 2D or 3D corrdinates.",
14766     __FILE__, VFitArea, group);
14767   theCommands.Add ("vzfit", "vzfit [scale]\n"
14768     "   Matches Z near, Z far view volume planes to the displayed objects.\n"
14769     "   \"scale\" - specifies factor to scale computed z range.\n",
14770     __FILE__, VZFit, group);
14771   theCommands.Add("vrepaint",
14772             "vrepaint [-immediate] [-continuous FPS]"
14773     "\n\t\t: force redraw of active View"
14774     "\n\t\t:   -immediate  flag performs redraw of immediate layers only;"
14775     "\n\t\t:   -continuous activates/deactivates continuous redraw of active View,"
14776     "\n\t\t:                0 means no continuous rendering,"
14777     "\n\t\t:               -1 means non-stop redraws,"
14778     "\n\t\t:               >0 specifies target framerate,",
14779     __FILE__,VRepaint,group);
14780   theCommands.Add("vclear",
14781     "vclear          : vclear"
14782     "\n\t\t: remove all the object from the viewer",
14783     __FILE__,VClear,group);
14784   theCommands.Add (
14785     "vbackground",
14786     "Changes background or some background settings.\n"
14787     "\n"
14788     "Usage:\n"
14789     "  vbackground -imageFile ImageFile [-imageMode FillType]\n"
14790     "  vbackground -imageMode FillType\n"
14791     "  vbackground -gradient Color1 Color2 [-gradientMode FillMethod]\n"
14792     "  vbackground -gradientMode FillMethod\n"
14793     "  vbackground -cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]\n"
14794     "  vbackground -color Color\n"
14795     "  vbackground -default -gradient Color1 Color2 [-gradientMode FillType]\n"
14796     "  vbackground -default -color Color\n"
14797     "  vbackground -help\n"
14798     "\n"
14799     "Options:\n"
14800     "  -imageFile    (-imgFile, -image, -img):             sets filename of image used as background\n"
14801     "  -imageMode    (-imgMode, -imageMd, -imgMd):         sets image fill type\n"
14802     "  -gradient     (-grad, -gr):                         sets background gradient starting and ending colors\n"
14803     "  -gradientMode (-gradMode, -gradMd, -grMode, -grMd): sets gradient fill method\n"
14804     "  -cubemap      (-cmap, -cm):                         sets environment cubemap as background\n"
14805     "  -invertedz    (-invz, -iz):                         sets inversion of Z axis for background cubemap rendering\n"
14806     "  -order        (-o):                                 defines order of tiles in one image cubemap\n"
14807     "                                                      (has no effect in case of multi image cubemaps)\n"
14808     "  -color        (-col):                               sets background color\n"
14809     "  -default      (-def):                               sets background default gradient or color\n"
14810     "  -help         (-h):                                 outputs short help message\n"
14811     "\n"
14812     "Arguments:\n"
14813     "  Color:        Red Green Blue  - where Red, Green, Blue must be integers within the range [0, 255]\n"
14814     "                                  or reals within the range [0.0, 1.0]\n"
14815     "                ColorName       - one of WHITE, BLACK, RED, GREEN, BLUE, etc.\n"
14816     "                #HHH, [#]HHHHHH - where H is a hexadecimal digit (0 .. 9, a .. f, or A .. F)\n"
14817     "  FillMethod:   one of NONE, HOR[IZONTAL], VER[TICAL], DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, "
14818     "CORNER4\n"
14819     "  FillType:     one of CENTERED, TILED, STRETCH, NONE\n"
14820     "  ImageFile:    a name of the file with the image used as a background\n"
14821     "  CubemapFilei: a name of the file with one image packed cubemap or names of separate files with every cubemap side\n"
14822     "  TileIndexi:   a cubemap side index in range [0, 5] for i tile of one image packed cubemap\n",
14823     __FILE__,
14824     vbackground,
14825     group);
14826   theCommands.Add ("vsetbg",
14827                    "Loads image as background."
14828                    "\n\t\t: vsetbg ImageFile [FillType]"
14829                    "\n\t\t: vsetbg -imageFile ImageFile [-imageMode FillType]"
14830                    "\n\t\t: Alias for 'vbackground -imageFile ImageFile [-imageMode FillType]'.",
14831                    __FILE__,
14832                    vbackground,
14833                    group);
14834   theCommands.Add ("vsetbgmode",
14835                    "Changes background image fill type."
14836                    "\n\t\t: vsetbgmode [-imageMode] FillType"
14837                    "\n\t\t: Alias for 'vbackground -imageMode FillType'.",
14838                    __FILE__,
14839                    vbackground,
14840                    group);
14841   theCommands.Add ("vsetgradientbg",
14842                    "Mounts gradient background."
14843                    "\n\t\t: vsetgradientbg Color1 Color2 [FillMethod]"
14844                    "\n\t\t: vsetgradientbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14845                    "\n\t\t: Alias for 'vbackground -gradient Color1 Color2 -gradientMode FillMethod'.",
14846                    __FILE__,
14847                    vbackground,
14848                    group);
14849   theCommands.Add ("vsetgrbgmode",
14850                    "Changes gradient background fill method."
14851                    "\n\t\t: vsetgrbgmode [-gradientMode] FillMethod"
14852                    "\n\t\t: Alias for 'vbackground -gradientMode FillMethod'.",
14853                    __FILE__,
14854                    vbackground,
14855                    group);
14856   theCommands.Add ("vsetcolorbg",
14857                    "Sets background color."
14858                    "\n\t\t: vsetcolorbg [-color] Color."
14859                    "\n\t\t: Alias for 'vbackground -color Color'.",
14860                    __FILE__,
14861                    vbackground,
14862                    group);
14863   theCommands.Add ("vsetdefaultbg",
14864                    "Sets default viewer background fill color (flat/gradient)."
14865                    "\n\t\t: vsetdefaultbg Color1 Color2 [FillMethod]"
14866                    "\n\t\t: vsetdefaultbg -gradient Color1 Color2 [-gradientMode FillMethod]"
14867                    "\n\t\t: Alias for 'vbackground -default -gradient Color1 Color2 [-gradientMode FillMethod]'."
14868                    "\n\t\t: vsetdefaultbg [-color] Color"
14869                    "\n\t\t: Alias for 'vbackground -default -color Color'.",
14870                    __FILE__,
14871                    vbackground,
14872                    group);
14873   theCommands.Add("vscale",
14874     "vscale          : vscale X Y Z",
14875     __FILE__,VScale,group);
14876   theCommands.Add("vzbufftrihedron",
14877             "vzbufftrihedron [{-on|-off}=-on] [-type {wireframe|zbuffer}=zbuffer]"
14878     "\n\t\t:       [-position center|left_lower|left_upper|right_lower|right_upper]"
14879     "\n\t\t:       [-scale value=0.1] [-size value=0.8] [-arrowDiam value=0.05]"
14880     "\n\t\t:       [-colorArrowX color=RED] [-colorArrowY color=GREEN] [-colorArrowZ color=BLUE]"
14881     "\n\t\t:       [-nbfacets value=12] [-colorLabels color=WHITE]"
14882     "\n\t\t:       [-colorLabelX color] [-colorLabelY color] [-colorLabelZ color]"
14883     "\n\t\t: Displays a trihedron",
14884     __FILE__,VZBuffTrihedron,group);
14885   theCommands.Add("vrotate",
14886     "vrotate [[-mouseStart X Y] [-mouseMove X Y]]|[AX AY AZ [X Y Z]]"
14887     "\n                : Option -mouseStart starts rotation according to the mouse position"
14888     "\n                : Option -mouseMove continues rotation with angle computed"
14889     "\n                : from last and new mouse position."
14890     "\n                : vrotate AX AY AZ [X Y Z]",
14891     __FILE__,VRotate,group);
14892   theCommands.Add("vzoom",
14893     "vzoom           : vzoom coef",
14894     __FILE__,VZoom,group);
14895   theCommands.Add("vpan",
14896     "vpan            : vpan dx dy",
14897     __FILE__,VPan,group);
14898   theCommands.Add("vcolorscale",
14899     "vcolorscale name [-noupdate|-update] [-demo]"
14900     "\n\t\t:       [-range RangeMin=0 RangeMax=1 NbIntervals=10]"
14901     "\n\t\t:       [-font HeightFont=20]"
14902     "\n\t\t:       [-logarithmic {on|off}=off] [-reversed {on|off}=off]"
14903     "\n\t\t:       [-smoothTransition {on|off}=off]"
14904     "\n\t\t:       [-hueRange MinAngle=230 MaxAngle=0]"
14905     "\n\t\t:       [-colorRange MinColor=BLUE1 MaxColor=RED]"
14906     "\n\t\t:       [-textpos {left|right|center|none}=right]"
14907     "\n\t\t:       [-labelAtBorder {on|off}=on]"
14908     "\n\t\t:       [-colors Color1 Color2 ...] [-color Index Color]"
14909     "\n\t\t:       [-labels Label1 Label2 ...] [-label Index Label]"
14910     "\n\t\t:       [-freeLabels NbOfLabels Label1 Label2 ...]"
14911     "\n\t\t:       [-xy Left=0 Bottom=0]"
14912     "\n\t\t:       [-uniform lightness hue_from hue_to]"
14913     "\n\t\t:  -demo     - displays a color scale with demonstratio values"
14914     "\n\t\t:  -colors   - set colors for all intervals"
14915     "\n\t\t:  -color    - set color for specific interval"
14916     "\n\t\t:  -uniform  - generate colors with the same lightness"
14917     "\n\t\t:  -textpos  - horizontal label position relative to color scale bar"
14918     "\n\t\t:  -labelAtBorder - vertical label position relative to color interval;"
14919     "\n\t\t:              at border means the value inbetween neighbor intervals,"
14920     "\n\t\t:              at center means the center value within current interval"
14921     "\n\t\t:  -labels   - set labels for all intervals"
14922     "\n\t\t:  -freeLabels - same as -labels but does not require"
14923     "\n\t\t:              matching the number of intervals"
14924     "\n\t\t:  -label    - set label for specific interval"
14925     "\n\t\t:  -title    - set title"
14926     "\n\t\t:  -reversed - setup smooth color transition between intervals"
14927     "\n\t\t:  -smoothTransition - swap colorscale direction"
14928     "\n\t\t:  -hueRange - set hue angles corresponding to minimum and maximum values",
14929     __FILE__, VColorScale, group);
14930   theCommands.Add("vgraduatedtrihedron",
14931     "vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]\n"
14932     "\t[-namefont Name] [-valuesfont Name]\n"
14933     "\t[-xdrawname on/off] [-ydrawname on/off] [-zdrawname on/off]\n"
14934     "\t[-xnameoffset IntVal] [-ynameoffset IntVal] [-znameoffset IntVal]"
14935     "\t[-xnamecolor Color] [-ynamecolor Color] [-znamecolor Color]\n"
14936     "\t[-xdrawvalues on/off] [-ydrawvalues on/off] [-zdrawvalues on/off]\n"
14937     "\t[-xvaluesoffset IntVal] [-yvaluesoffset IntVal] [-zvaluesoffset IntVal]"
14938     "\t[-xcolor Color] [-ycolor Color] [-zcolor Color]\n"
14939     "\t[-xdrawticks on/off] [-ydrawticks on/off] [-zdrawticks on/off]\n"
14940     "\t[-xticks Number] [-yticks Number] [-zticks Number]\n"
14941     "\t[-xticklength IntVal] [-yticklength IntVal] [-zticklength IntVal]\n"
14942     "\t[-drawgrid on/off] [-drawaxes on/off]\n"
14943     " - Displays or erases graduated trihedron"
14944     " - xname, yname, zname - names of axes, default: X, Y, Z\n"
14945     " - namefont - font of axes names. Default: Arial\n"
14946     " - xnameoffset, ynameoffset, znameoffset - offset of name from values or tickmarks or axis. Default: 30\n"
14947     " - xnamecolor, ynamecolor, znamecolor - colors of axes names\n"
14948     " - xvaluesoffset, yvaluesoffset, zvaluesoffset - offset of values from tickmarks or axis. Default: 10\n"
14949     " - valuesfont - font of axes values. Default: Arial\n"
14950     " - xcolor, ycolor, zcolor - color of axis and values\n"
14951     " - xticks, yticks, xzicks - number of tickmark on axes. Default: 5\n"
14952     " - xticklength, yticklength, xzicklength - length of tickmark on axes. Default: 10\n",
14953     __FILE__,VGraduatedTrihedron,group);
14954   theCommands.Add("vtile" ,
14955             "vtile [-totalSize W H] [-lowerLeft X Y] [-upperLeft X Y] [-tileSize W H]"
14956     "\n\t\t: Setup view to draw a tile (a part of virtual bigger viewport)."
14957     "\n\t\t:  -totalSize the size of virtual bigger viewport"
14958     "\n\t\t:  -tileSize  tile size (the view size will be used if omitted)"
14959     "\n\t\t:  -lowerLeft tile offset as lower left corner"
14960     "\n\t\t:  -upperLeft tile offset as upper left corner",
14961     __FILE__, VTile, group);
14962   theCommands.Add("vzlayer",
14963               "vzlayer [layerId]"
14964       "\n\t\t:         [-add|-delete|-get|-settings] [-insertBefore AnotherLayer] [-insertAfter AnotherLayer]"
14965       "\n\t\t:         [-origin X Y Z] [-cullDist Distance] [-cullSize Size]"
14966       "\n\t\t:         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]"
14967       "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv|rayTracing}]"
14968       "\n\t\t: ZLayer list management:"
14969       "\n\t\t:   -add      add new z layer to viewer and print its id"
14970       "\n\t\t:   -insertBefore add new z layer and insert it before existing one"
14971       "\n\t\t:   -insertAfter  add new z layer and insert it after  existing one"
14972       "\n\t\t:   -delete   delete z layer"
14973       "\n\t\t:   -get      print sequence of z layers"
14974       "\n\t\t:   -settings print status of z layer settings"
14975       "\n\t\t:   -disable  disables given setting"
14976       "\n\t\t:   -enable   enables  given setting",
14977     __FILE__,VZLayer,group);
14978   theCommands.Add("vlayerline",
14979     "vlayerline : vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]",
14980     __FILE__,VLayerLine,group);
14981   theCommands.Add("vgrid",
14982               "vgrid [off] [-type {rect|circ}] [-mode {line|point}] [-origin X Y] [-rotAngle Angle] [-zoffset DZ]"
14983       "\n\t\t:       [-step X Y] [-size DX DY]"
14984       "\n\t\t:       [-step StepRadius NbDivisions] [-radius Radius]",
14985     __FILE__, VGrid, group);
14986   theCommands.Add ("vpriviledgedplane",
14987     "vpriviledgedplane [Ox Oy Oz Nx Ny Nz [Xx Xy Xz]]"
14988     "\n\t\t:   Ox, Oy, Oz - plane origin"
14989     "\n\t\t:   Nx, Ny, Nz - plane normal direction"
14990     "\n\t\t:   Xx, Xy, Xz - plane x-reference axis direction"
14991     "\n\t\t: Sets or prints viewer's priviledged plane geometry.",
14992     __FILE__, VPriviledgedPlane, group);
14993   theCommands.Add ("vconvert",
14994     "vconvert v [Mode={window|view}]"
14995     "\n\t\t: vconvert x y [Mode={window|view|grid|ray}]"
14996     "\n\t\t: vconvert x y z [Mode={window|grid}]"
14997     "\n\t\t:   window - convert to window coordinates, pixels"
14998     "\n\t\t:   view   - convert to view projection plane"
14999     "\n\t\t:   grid   - convert to model coordinates, given on grid"
15000     "\n\t\t:   ray    - convert projection ray to model coordinates"
15001     "\n\t\t: - vconvert v window : convert view to window;"
15002     "\n\t\t: - vconvert v view   : convert window to view;"
15003     "\n\t\t: - vconvert x y window : convert view to window;"
15004     "\n\t\t: - vconvert x y view : convert window to view;"
15005     "\n\t\t: - vconvert x y : convert window to model;"
15006     "\n\t\t: - vconvert x y grid : convert window to model using grid;"
15007     "\n\t\t: - vconvert x y ray : convert window projection line to model;"
15008     "\n\t\t: - vconvert x y z window : convert model to window;"
15009     "\n\t\t: - vconvert x y z grid : convert view to model using grid;"
15010     "\n\t\t: Converts the given coordinates to window/view/model space.",
15011     __FILE__, VConvert, group);
15012   theCommands.Add ("vfps",
15013     "vfps [framesNb=100] [-duration seconds] : estimate average frame rate for active view",
15014     __FILE__, VFps, group);
15015   theCommands.Add ("vgldebug",
15016             "vgldebug [-sync {0|1}] [-debug {0|1}] [-glslWarn {0|1}]"
15017     "\n\t\t:          [-glslCode {off|short|full}] [-extraMsg {0|1}] [{0|1}]"
15018     "\n\t\t: Request debug GL context. Should be called BEFORE vinit."
15019     "\n\t\t: Debug context can be requested only on Windows"
15020     "\n\t\t: with GL_ARB_debug_output extension implemented by GL driver!"
15021     "\n\t\t:  -sync     - request synchronized debug GL context"
15022     "\n\t\t:  -glslWarn - log GLSL compiler/linker warnings,"
15023     "\n\t\t:              which are suppressed by default,"
15024     "\n\t\t:  -glslCode - log GLSL program source code,"
15025     "\n\t\t:              which are suppressed by default,"
15026     "\n\t\t:  -extraMsg - log extra diagnostic messages from GL context,"
15027     "\n\t\t:              which are suppressed by default",
15028     __FILE__, VGlDebug, group);
15029   theCommands.Add ("vvbo",
15030     "vvbo [{0|1}] : turn VBO usage On/Off; affects only newly displayed objects",
15031     __FILE__, VVbo, group);
15032   theCommands.Add ("vstereo",
15033             "vstereo [0|1] [-mode Mode] [-reverse {0|1}]"
15034     "\n\t\t:         [-mirrorComposer] [-hmdfov2d AngleDegrees] [-unitFactor MetersFactor]"
15035     "\n\t\t:         [-anaglyph Filter]"
15036     "\n\t\t: Control stereo output mode."
15037     "\n\t\t: When -mirrorComposer is specified, VR rendered frame will be mirrored in window (debug)."
15038     "\n\t\t: Parameter -unitFactor specifies meters scale factor for mapping VR input."
15039     "\n\t\t: Available modes for -mode:"
15040     "\n\t\t:  quadBuffer        - OpenGL QuadBuffer stereo,"
15041     "\n\t\t:                     requires driver support."
15042     "\n\t\t:                     Should be called BEFORE vinit!"
15043     "\n\t\t:  anaglyph         - Anaglyph glasses"
15044     "\n\t\t:  rowInterlaced    - row-interlaced display"
15045     "\n\t\t:  columnInterlaced - column-interlaced display"
15046     "\n\t\t:  chessBoard       - chess-board output"
15047     "\n\t\t:  sideBySide       - horizontal pair"
15048     "\n\t\t:  overUnder        - vertical   pair"
15049     "\n\t\t:  openVR           - OpenVR (HMD)"
15050     "\n\t\t: Available Anaglyph filters for -anaglyph:"
15051     "\n\t\t:  redCyan, redCyanSimple, yellowBlue, yellowBlueSimple,"
15052     "\n\t\t:  greenMagentaSimple",
15053     __FILE__, VStereo, group);
15054   theCommands.Add ("vcaps",
15055             "vcaps [-sRGB {0|1}] [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]"
15056     "\n\t\t:       [-compatibleProfile {0|1}] [-compressedTextures {0|1}]"
15057     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}] [-opaqueAlpha {0|1}]"
15058     "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
15059     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
15060     "\n\t\t:       [-noExtensions {0|1}] [-maxVersion Major Minor]"
15061     "\n\t\t: Modify particular graphic driver options:"
15062     "\n\t\t:  sRGB     - enable/disable sRGB rendering"
15063     "\n\t\t:  FFP      - use fixed-function pipeline instead of"
15064     "\n\t\t:             built-in GLSL programs"
15065     "\n\t\t:            (requires compatible profile)"
15066     "\n\t\t:  polygonMode - use Polygon Mode instead of built-in GLSL programs"
15067     "\n\t\t:  compressedTexture - allow uploading of GPU-supported compressed texture formats"
15068     "\n\t\t:  VBO      - use Vertex Buffer Object (copy vertex"
15069     "\n\t\t:             arrays to GPU memory)"
15070     "\n\t\t:  sprite   - use textured sprites instead of bitmaps"
15071     "\n\t\t:  vsync    - switch VSync on or off"
15072     "\n\t\t:  opaqueAlpha - disable writes in alpha component of color buffer"
15073     "\n\t\t:  winBuffer - allow using window buffer for rendering"
15074     "\n\t\t: Context creation options:"
15075     "\n\t\t:  softMode          - software OpenGL implementation"
15076     "\n\t\t:  compatibleProfile - backward-compatible profile"
15077     "\n\t\t:  quadbuffer        - QuadBuffer"
15078     "\n\t\t:  noExtensions      - disallow usage of extensions"
15079     "\n\t\t:  maxVersion        - force upper OpenGL version to be used"
15080     "\n\t\t: Unlike vrenderparams, these parameters control alternative"
15081     "\n\t\t: rendering paths producing the same visual result when"
15082     "\n\t\t: possible."
15083     "\n\t\t: Command is intended for testing old hardware compatibility.",
15084     __FILE__, VCaps, group);
15085   theCommands.Add ("vmemgpu",
15086     "vmemgpu [f]: print system-dependent GPU memory information if available;"
15087     " with f option returns free memory in bytes",
15088     __FILE__, VMemGpu, group);
15089   theCommands.Add ("vreadpixel",
15090     "vreadpixel xPixel yPixel [{rgb|rgba|sRGB|sRGBa|depth|hls|rgbf|rgbaf}=rgba] [-name|-hex]"
15091     " : Read pixel value for active view",
15092     __FILE__, VReadPixel, group);
15093   theCommands.Add("diffimage",
15094             "diffimage imageFile1 imageFile2 [diffImageFile]"
15095     "\n\t\t:           [-toleranceOfColor {0..1}=0] [-blackWhite {on|off}=off] [-borderFilter {on|off}=off]"
15096     "\n\t\t:           [-display viewName prsName1 prsName2 prsNameDiff] [-exitOnClose] [-closeOnEscape]"
15097     "\n\t\t: Compare two images by content and generate difference image."
15098     "\n\t\t: When -exitOnClose is specified, closing the view will exit application."
15099     "\n\t\t: When -closeOnEscape is specified, view will be closed on pressing Escape.",
15100     __FILE__, VDiffImage, group);
15101   theCommands.Add ("vselect",
15102     "vselect x1 y1 [x2 y2 [x3 y3 ... xn yn]] [-allowoverlap 0|1] [shift_selection = 0|1]\n"
15103     "- emulates different types of selection:\n"
15104     "- 1) single click selection\n"
15105     "- 2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)\n"
15106     "- 3) selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn)\n"
15107     "- 4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.\n"
15108     "     If the flag is set to 1, both sensitives that were included completely and overlapped partially by defined \n"
15109     "     rectangle or polygon will be detected, otherwise algorithm will chose only fully included sensitives.\n"
15110     "     Default behavior is to detect only full inclusion. (partial inclusion - overlap - is not allowed by default)\n"
15111     "- 5) any of these selections with shift button pressed",
15112     __FILE__, VSelect, group);
15113   theCommands.Add ("vmoveto",
15114     "vmoveto [x y] [-reset]"
15115     "\n\t\t: Emulates cursor movement to pixel position (x,y)."
15116     "\n\t\t:   -reset resets current highlighting",
15117     __FILE__, VMoveTo, group);
15118   theCommands.Add ("vviewparams",
15119               "vviewparams [-args] [-scale [s]]"
15120       "\n\t\t:             [-eye [x y z]] [-at [x y z]] [-up [x y z]]"
15121       "\n\t\t:             [-proj [x y z]] [-center x y] [-size sx]"
15122       "\n\t\t: Manage current view parameters or prints all"
15123       "\n\t\t: current values when called without argument."
15124       "\n\t\t:   -scale [s]    prints or sets viewport relative scale"
15125       "\n\t\t:   -eye  [x y z] prints or sets eye location"
15126       "\n\t\t:   -at   [x y z] prints or sets center of look"
15127       "\n\t\t:   -up   [x y z] prints or sets direction of up vector"
15128       "\n\t\t:   -proj [x y z] prints or sets direction of look"
15129       "\n\t\t:   -center x y   sets location of center of the screen in pixels"
15130       "\n\t\t:   -size [sx]    prints viewport projection width and height sizes"
15131       "\n\t\t:                 or changes the size of its maximum dimension"
15132       "\n\t\t:   -args         prints vviewparams arguments for restoring current view",
15133     __FILE__, VViewParams, group);
15134
15135   theCommands.Add("v2dmode",
15136     "v2dmode [-name viewName] [-mode {-on|-off}=-on]"
15137     "\n\t\t:   name   - name of existing view, if not defined, the active view is changed"
15138     "\n\t\t:   mode   - switches On/Off rotation mode"
15139     "\n\t\t: Set 2D mode of the active viewer manipulating. The following mouse and key actions are disabled:"
15140     "\n\t\t:   - rotation of the view by 3rd mouse button with Ctrl active"
15141     "\n\t\t:   - set view projection using key buttons: A/D/T/B/L/R for AXO, Reset, Top, Bottom, Left, Right"
15142     "\n\t\t: View camera position might be changed only by commands.",
15143     __FILE__, V2DMode, group);
15144
15145   theCommands.Add("vanimation", "Alias for vanim",
15146     __FILE__, VAnimation, group);
15147
15148   theCommands.Add("vanim",
15149             "List existing animations:"
15150     "\n\t\t:  vanim"
15151     "\n\t\t: Animation playback:"
15152     "\n\t\t:  vanim name -play|-resume [playFrom [playDuration]]"
15153     "\n\t\t:            [-speed Coeff] [-freeLook] [-lockLoop]"
15154     "\n\t\t:   -speed    playback speed (1.0 is normal speed)"
15155     "\n\t\t:   -freeLook skip camera animations"
15156     "\n\t\t:   -lockLoop disable any interactions"
15157     "\n\t\t:"
15158     "\n\t\t: Animation definition:"
15159     "\n\t\t:  vanim Name/sub/name [-clear] [-delete]"
15160     "\n\t\t:        [start TimeSec] [duration TimeSec]"
15161     "\n\t\t:"
15162     "\n\t\t: Animation name defined in path-style (anim/name or anim.name)"
15163     "\n\t\t: specifies nested animations."
15164     "\n\t\t: There is no syntax to explicitly add new animation,"
15165     "\n\t\t: and all non-existing animations within the name will be"
15166     "\n\t\t: implicitly created on first use (including parents)."
15167     "\n\t\t:"
15168     "\n\t\t: Each animation might define the SINGLE action (see below),"
15169     "\n\t\t: like camera transition, object transformation or custom callback."
15170     "\n\t\t: Child animations can be used for defining concurrent actions."
15171     "\n\t\t:"
15172     "\n\t\t: Camera animation:"
15173     "\n\t\t:  vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]"
15174     "\n\t\t:                   [-at1  X Y Z] [-at2  X Y Z]"
15175     "\n\t\t:                   [-up1  X Y Z] [-up2  X Y Z]"
15176     "\n\t\t:                   [-scale1 Scale] [-scale2 Scale]"
15177     "\n\t\t:   -eyeX   camera Eye positions pair (start and end)"
15178     "\n\t\t:   -atX    camera Center positions pair"
15179     "\n\t\t:   -upX    camera Up directions pair"
15180     "\n\t\t:   -scaleX camera Scale factors pair"
15181     "\n\t\t: Object animation:"
15182     "\n\t\t:  vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]"
15183     "\n\t\t:                     [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]"
15184     "\n\t\t:                     [-scale1 Scale] [-scale2 Scale]"
15185     "\n\t\t:   -locX   object Location points pair (translation)"
15186     "\n\t\t:   -rotX   object Orientations pair (quaternions)"
15187     "\n\t\t:   -scaleX object Scale factors pair (quaternions)"
15188     "\n\t\t: Custom callback:"
15189     "\n\t\t:  vanim name -invoke \"Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN\""
15190     "\n\t\t:   %Pts        overall animation presentation timestamp"
15191     "\n\t\t:   %LocalPts   local animation timestamp"
15192     "\n\t\t:   %Normalized local animation normalized value in range 0..1"
15193     "\n\t\t:"
15194     "\n\t\t: Video recording:"
15195     "\n\t\t:  vanim name -record FileName [Width Height] [-fps FrameRate=24]"
15196     "\n\t\t:             [-format Format] [-vcodec Codec] [-pix_fmt PixelFormat]"
15197     "\n\t\t:             [-crf Value] [-preset Preset]"
15198     "\n\t\t:   -fps     video framerate"
15199     "\n\t\t:   -format  file format, container (matroska, etc.)"
15200     "\n\t\t:   -vcodec  video codec identifier (ffv1, mjpeg, etc.)"
15201     "\n\t\t:   -pix_fmt image pixel format (yuv420p, rgb24, etc.)"
15202     "\n\t\t:   -crf     constant rate factor (specific to codec)"
15203     "\n\t\t:   -preset  codec parameters preset (specific to codec)"
15204     __FILE__, VAnimation, group);
15205
15206   theCommands.Add("vchangeselected",
15207     "vchangeselected shape"
15208     "- adds to shape to selection or remove one from it",
15209                 __FILE__, VChangeSelected, group);
15210   theCommands.Add ("vnbselected",
15211     "vnbselected"
15212     "\n\t\t: Returns number of selected objects", __FILE__, VNbSelected, group);
15213   theCommands.Add ("vcamera",
15214               "vcamera [PrsName] [-ortho] [-projtype]"
15215       "\n\t\t:         [-persp]"
15216       "\n\t\t:         [-fovy   [Angle]] [-distance [Distance]]"
15217       "\n\t\t:         [-stereo] [-leftEye] [-rightEye]"
15218       "\n\t\t:         [-iod [Distance]] [-iodType    [absolute|relative]]"
15219       "\n\t\t:         [-zfocus [Value]] [-zfocusType [absolute|relative]]"
15220       "\n\t\t:         [-fov2d  [Angle]] [-lockZup {0|1}]"
15221       "\n\t\t:         [-xrPose base|head=base]"
15222       "\n\t\t: Manages camera parameters."
15223       "\n\t\t: Displays frustum when presentation name PrsName is specified."
15224       "\n\t\t: Prints current value when option called without argument."
15225       "\n\t\t: Orthographic camera:"
15226       "\n\t\t:   -ortho      activate orthographic projection"
15227       "\n\t\t: Perspective camera:"
15228       "\n\t\t:   -persp      activate perspective  projection (mono)"
15229       "\n\t\t:   -fovy       field of view in y axis, in degrees"
15230       "\n\t\t:   -fov2d      field of view limit for 2d on-screen elements"
15231       "\n\t\t:   -distance   distance of eye from camera center"
15232       "\n\t\t:   -lockZup    lock Z up (tunrtable mode)"
15233       "\n\t\t: Stereoscopic camera:"
15234       "\n\t\t:   -stereo     perspective  projection (stereo)"
15235       "\n\t\t:   -leftEye    perspective  projection (left  eye)"
15236       "\n\t\t:   -rightEye   perspective  projection (right eye)"
15237       "\n\t\t:   -iod        intraocular distance value"
15238       "\n\t\t:   -iodType    distance type, absolute or relative"
15239       "\n\t\t:   -zfocus     stereographic focus value"
15240       "\n\t\t:   -zfocusType focus type, absolute or relative",
15241     __FILE__, VCamera, group);
15242   theCommands.Add ("vautozfit", "command to enable or disable automatic z-range adjusting\n"
15243     "- vautozfit [on={1|0}] [scale]\n"
15244     "    Prints or changes parameters of automatic z-fit mode:\n"
15245     "   \"on\" - turns automatic z-fit on or off\n"
15246     "   \"scale\" - specifies factor to scale computed z range.\n",
15247     __FILE__, VAutoZFit, group);
15248   theCommands.Add ("vzrange", "command to manually access znear and zfar values\n"
15249     "   vzrange                - without parameters shows current values\n"
15250     "   vzrange [znear] [zfar] - applies provided values to view",
15251     __FILE__,VZRange, group);
15252   theCommands.Add ("vpurgedisplay",
15253     "vpurgedisplay"
15254     "- removes structures which don't belong to objects displayed in neutral point",
15255     __FILE__, VPurgeDisplay, group);
15256   theCommands.Add("vsetviewsize",
15257     "vsetviewsize size",
15258     __FILE__,VSetViewSize,group);
15259   theCommands.Add("vmoveview",
15260     "vmoveview Dx Dy Dz [Start = 1|0]",
15261     __FILE__,VMoveView,group);
15262   theCommands.Add("vtranslateview",
15263     "vtranslateview Dx Dy Dz [Start = 1|0)]",
15264     __FILE__,VTranslateView,group);
15265   theCommands.Add("vturnview",
15266     "vturnview Ax Ay Az [Start = 1|0]",
15267     __FILE__,VTurnView,group);
15268   theCommands.Add("vtextureenv",
15269     "Enables or disables environment mapping in the 3D view, loading the texture from the given standard "
15270     "or user-defined file and optionally applying texture mapping parameters\n"
15271     "                  Usage:\n"
15272     "                  vtextureenv off - disables environment mapping\n"
15273     "                  vtextureenv on {std_texture|texture_file_name} [rep mod flt ss st ts tt rot] - enables environment mapping\n"
15274     "                              std_texture = (0..7)\n"
15275     "                              rep         = {clamp|repeat}\n"
15276     "                              mod         = {decal|modulate}\n"
15277     "                              flt         = {nearest|bilinear|trilinear}\n"
15278     "                              ss, st      - scale factors for s and t texture coordinates\n"
15279     "                              ts, tt      - translation for s and t texture coordinates\n"
15280     "                              rot         - texture rotation angle in degrees",
15281     __FILE__, VTextureEnv, group);
15282   theCommands.Add("vhlr",
15283             "vhlr {on|off} [-showHidden={1|0}] [-algoType={algo|polyAlgo}] [-noupdate]"
15284       "\n\t\t: Hidden Line Removal algorithm."
15285       "\n\t\t:   -showHidden if set ON, hidden lines are drawn as dotted ones"
15286       "\n\t\t:   -algoType   type of HLR algorithm.\n",
15287     __FILE__,VHLR,group);
15288   theCommands.Add("vhlrtype",
15289               "vhlrtype {algo|polyAlgo} [shape_1 ... shape_n] [-noupdate]"
15290       "\n\t\t: Changes the type of HLR algorithm using for shapes:"
15291       "\n\t\t:   'algo' - exact HLR algorithm is applied"
15292       "\n\t\t:   'polyAlgo' - polygonal HLR algorithm is applied"
15293       "\n\t\t: If shapes are not given - option is applied to all shapes in the view",
15294     __FILE__,VHLRType,group);
15295   theCommands.Add("vclipplane",
15296               "vclipplane planeName [{0|1}]"
15297       "\n\t\t:   [-equation1 A B C D]"
15298       "\n\t\t:   [-equation2 A B C D]"
15299       "\n\t\t:   [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]"
15300       "\n\t\t:   [-set|-unset|-setOverrideGlobal [objects|views]]"
15301       "\n\t\t:   [-maxPlanes]"
15302       "\n\t\t:   [-capping {0|1}]"
15303       "\n\t\t:     [-color R G B] [-transparency Value] [-hatch {on|off|ID}]"
15304       "\n\t\t:     [-texName Texture] [-texScale SX SY] [-texOrigin TX TY]"
15305       "\n\t\t:       [-texRotate Angle]"
15306       "\n\t\t:     [-useObjMaterial {0|1}] [-useObjTexture {0|1}]"
15307       "\n\t\t:       [-useObjShader {0|1}]"
15308       "\n\t\t: Clipping planes management:"
15309       "\n\t\t:   -maxPlanes   print plane limit for view"
15310       "\n\t\t:   -delete      delete plane with given name"
15311       "\n\t\t:   {off|on|0|1} turn clipping on/off"
15312       "\n\t\t:   -set|-unset  set/unset plane for Object or View list;"
15313       "\n\t\t:                applied to active View when list is omitted"
15314       "\n\t\t:   -equation A B C D change plane equation"
15315       "\n\t\t:   -clone SourcePlane NewPlane clone the plane definition."
15316       "\n\t\t: Capping options:"
15317       "\n\t\t:   -capping {off|on|0|1} turn capping on/off"
15318       "\n\t\t:   -color R G B          set capping color"
15319       "\n\t\t:   -transparency Value   set capping transparency 0..1"
15320       "\n\t\t:   -texName Texture      set capping texture"
15321       "\n\t\t:   -texScale SX SY       set capping tex scale"
15322       "\n\t\t:   -texOrigin TX TY      set capping tex origin"
15323       "\n\t\t:   -texRotate Angle      set capping tex rotation"
15324       "\n\t\t:   -hatch {on|off|ID}    set capping hatching mask"
15325       "\n\t\t:   -useObjMaterial {off|on|0|1} use material of clipped object"
15326       "\n\t\t:   -useObjTexture  {off|on|0|1} use texture of clipped object"
15327       "\n\t\t:   -useObjShader   {off|on|0|1} use shader program of object",
15328       __FILE__, VClipPlane, group);
15329   theCommands.Add("vdefaults",
15330                "vdefaults [-absDefl value]"
15331        "\n\t\t:           [-devCoeff value]"
15332        "\n\t\t:           [-angDefl value]"
15333        "\n\t\t:           [-autoTriang {off/on | 0/1}]"
15334     , __FILE__, VDefaults, group);
15335   theCommands.Add("vlight",
15336     "tool to manage light sources, without arguments shows list of lights."
15337     "\n    Main commands: "
15338     "\n      '-clear' to clear lights"
15339     "\n      '-{def}aults' to load default lights"
15340     "\n      '-add' <type> to add any light source"
15341     "\n          where <type> is one of {amb}ient|directional|{spot}light|positional"
15342     "\n      'change' <lightId> to edit light source with specified lightId"
15343     "\n\n      In addition to 'add' and 'change' commands you can use light parameters:"
15344     "\n        -layer Id"
15345     "\n        -{pos}ition X Y Z"
15346     "\n        -{dir}ection X Y Z (for directional light or for spotlight)"
15347     "\n        -color colorName"
15348     "\n        -{head}light 0|1"
15349     "\n        -castShadows 0|1"
15350     "\n        -{sm}oothness value"
15351     "\n        -{int}ensity value"
15352     "\n        -{constAtten}uation value"
15353     "\n        -{linearAtten}uation value"
15354     "\n        -angle angleDeg"
15355     "\n        -{spotexp}onent value"
15356     "\n        -range value"
15357     "\n        -local|-global"
15358     "\n        -name value"
15359     "\n        -display nameOfLight (display light source with specified nameOfLight or its name)"
15360     "\n        -showName  {1|0} show/hide the name of light source; 1 by default"
15361     "\n        -showRange {1|0} show/hide the range of spot/positional light source; 1 by default"
15362     "\n        -prsZoomable {1|0} make light presentation zoomable/non-zoomable"
15363     "\n        -prsSize {Value} set light presentation size"
15364     "\n\n      example: vlight -add positional -head 1 -pos 0 1 1 -color red"
15365     "\n        example: vlight -change 0 -direction 0 -1 0 -linearAttenuation 0.2",
15366     __FILE__, VLight, group);
15367   theCommands.Add("vpbrenv",
15368     "vpbrenv -clear|-generate"
15369     "\n\t\t: Clears or generates PBR environment map of active view."
15370     "\n\t\t:  -clear clears PBR environment (fills by white color)"
15371     "\n\t\t:  -generate generates PBR environment from current background cubemap",
15372     __FILE__, VPBREnvironment, group);
15373   theCommands.Add("vraytrace",
15374             "vraytrace [0|1]"
15375     "\n\t\t: Turns on/off ray-tracing renderer."
15376     "\n\t\t:   'vraytrace 0' alias for 'vrenderparams -raster'."
15377     "\n\t\t:   'vraytrace 1' alias for 'vrenderparams -rayTrace'.",
15378     __FILE__, VRenderParams, group);
15379   theCommands.Add("vrenderparams",
15380     "\n\t\t: Manages rendering parameters, affecting visual appearance, quality and performance."
15381     "\n\t\t: Should be applied taking into account GPU hardware capabilities and performance."
15382     "\n\t\t: Common parameters:"
15383     "\n\t\t: vrenderparams [-raster] [-shadingModel {unlit|facet|gouraud|phong|pbr|pbr_facet}=gouraud]"
15384     "\n\t\t:               [-msaa 0..8=0] [-rendScale scale=1] [-resolution value=72]"
15385     "\n\t\t:               [-oit {off|0.0-1.0}=off]"
15386     "\n\t\t:               [-shadows {on|off}=on] [-shadowMapResolution value=1024] [-shadowMapBias value=0.005]"
15387     "\n\t\t:               [-depthPrePass {on|off}=off] [-alphaToCoverage {on|off}=on]"
15388     "\n\t\t:               [-frustumCulling {on|off|noupdate}=on] [-lineFeather width=1.0]"
15389     "\n\t\t:               [-sync {default|views}] [-reset]"
15390     "\n\t\t:   -raster          Disables GPU ray-tracing."
15391     "\n\t\t:   -shadingModel    Controls shading model."
15392     "\n\t\t:   -msaa            Specifies number of samples for MSAA."
15393     "\n\t\t:   -rendScale       Rendering resolution scale factor (supersampling, alternative to MSAA)."
15394     "\n\t\t:   -resolution      Sets new pixels density (PPI) used as text scaling factor."
15395     "\n\t\t:   -lineFeather     Sets line feather factor while displaying mesh edges."
15396     "\n\t\t:   -alphaToCoverage Enables/disables alpha to coverage (needs MSAA)."
15397     "\n\t\t:   -oit             Enables/disables order-independent transparency (OIT) rendering;"
15398     "\n\t\t:                    weight OIT fixes transparency artifacts at the cost of blurry result,"
15399     "\n\t\t:                    it is managed by depth weight factor (0.0 value also enables weight OIT)."
15400     "\n\t\t:   -shadows         Enables/disables shadows rendering."
15401     "\n\t\t:   -shadowMapResolution Shadow texture map resolution."
15402     "\n\t\t:   -shadowMapBias   Shadow map bias."
15403     "\n\t\t:   -depthPrePass    Enables/disables depth pre-pass."
15404     "\n\t\t:   -frustumCulling  Enables/disables objects frustum clipping or"
15405     "\n\t\t:                    sets state to check structures culled previously."
15406     "\n\t\t:   -sync            Sets active View parameters as Viewer defaults / to other Views."
15407     "\n\t\t:   -reset           Resets active View parameters to Viewer defaults."
15408     "\n\t\t: Diagnostic output (on-screen overlay):"
15409     "\n\t\t: vrenderparams [-perfCounters none|fps|cpu|layers|structures|groups|arrays|triangles|points"
15410     "\n\t\t:                             |gpuMem|frameTime|basic|extended|full|nofps|skipImmediate]"
15411     "\n\t\t:               [-perfUpdateInterval nbSeconds=1] [-perfChart nbFrames=1] [-perfChartMax seconds=0.1]"
15412     "\n\t\t:   -perfCounters       Show/hide performance counters (flags can be combined)."
15413     "\n\t\t:   -perfUpdateInterval Performance counters update interval."
15414     "\n\t\t:   -perfChart          Show frame timers chart limited by specified number of frames."
15415     "\n\t\t:   -perfChartMax       Maximum time in seconds with the chart."
15416     "\n\t\t: Ray-Tracing options:"
15417     "\n\t\t: vrenderparams [-rayTrace] [-rayDepth {0..10}=3] [-reflections {on|off}=off]"
15418     "\n\t\t:               [-fsaa {on|off}=off] [-gleam {on|off}=off] [-env {on|off}=off]"
15419     "\n\t\t:               [-gi {on|off}=off] [-brng {on|off}=off]"
15420     "\n\t\t:               [-iss {on|off}=off] [-tileSize {1..4096}=32] [-nbTiles {64..1024}=256]"
15421     "\n\t\t:               [-ignoreNormalMap {on|off}=off] [-twoSide {on|off}=off]"
15422     "\n\t\t:               [-maxRad {value>0}=30.0]"
15423     "\n\t\t:               [-aperture {value>=0}=0.0] [-focal {value>=0.0}=1.0]"
15424     "\n\t\t:               [-exposure value=0.0] [-whitePoint value=1.0] [-toneMapping {disabled|filmic}=disabled]"
15425     "\n\t\t:   -rayTrace     Enables  GPU ray-tracing."
15426     "\n\t\t:   -rayDepth     Defines maximum ray-tracing depth."
15427     "\n\t\t:   -reflections  Enables/disables specular reflections."
15428     "\n\t\t:   -fsaa         Enables/disables adaptive anti-aliasing."
15429     "\n\t\t:   -gleam        Enables/disables transparency shadow effects."
15430     "\n\t\t:   -gi           Enables/disables global illumination effects (Path-Tracing)."
15431     "\n\t\t:   -env          Enables/disables environment map background."
15432     "\n\t\t:   -ignoreNormalMap Enables/disables normal map ignoring during path tracing."
15433     "\n\t\t:   -twoSide      Enables/disables two-sided BSDF models (PT mode)."
15434     "\n\t\t:   -iss          Enables/disables adaptive screen sampling (PT mode)."
15435     "\n\t\t:   -maxRad       Value used for clamping radiance estimation (PT mode)."
15436     "\n\t\t:   -tileSize     Specifies   size of screen tiles in ISS mode (32 by default)."
15437     "\n\t\t:   -nbTiles      Specifies number of screen tiles per Redraw in ISS mode (256 by default)."
15438     "\n\t\t:   -aperture     Aperture size  of perspective camera for depth-of-field effect (0 disables DOF)."
15439     "\n\t\t:   -focal        Focal distance of perspective camera for depth-of-field effect."
15440     "\n\t\t:   -exposure     Exposure value for tone mapping (0.0 value disables the effect)."
15441     "\n\t\t:   -whitePoint   White point value for filmic tone mapping."
15442     "\n\t\t:   -toneMapping  Tone mapping mode (disabled, filmic)."
15443     "\n\t\t: PBR environment baking parameters (advanced/debug):"
15444     "\n\t\t: vrenderparams [-pbrEnvPow2size {power>0}=9] [-pbrEnvSMLN {levels>1}=6] [-pbrEnvBP {0..1}=0.99]"
15445     "\n\t\t:               [-pbrEnvBDSN {samples>0}=1024] [-pbrEnvBSSN {samples>0}=256]"
15446     "\n\t\t:   -pbrEnvPow2size Controls size of IBL maps (real size can be calculates as 2^pbrenvpow2size)."
15447     "\n\t\t:   -pbrEnvSMLN     Controls number of mipmap levels used in specular IBL map."
15448     "\n\t\t:   -pbrEnvBDSN     Controls number of samples in Monte-Carlo integration during"
15449     "\n\t\t:                   diffuse IBL map's sherical harmonics calculation."
15450     "\n\t\t:   -pbrEnvBSSN     Controls maximum number of samples per mipmap level"
15451     "\n\t\t:                   in Monte-Carlo integration during specular IBL maps generation."
15452     "\n\t\t:   -pbrEnvBP       Controls strength of samples number reducing"
15453     "\n\t\t:                   during specular IBL maps generation (1 disables reducing)."
15454     "\n\t\t: Debug options:"
15455     "\n\t\t: vrenderparams [-issd {on|off}=off] [-rebuildGlsl on|off]"
15456     "\n\t\t:   -issd         Shows screen sampling distribution in ISS mode."
15457     "\n\t\t:   -rebuildGlsl  Rebuild Ray-Tracing GLSL programs (for debugging)."
15458     "\n\t\t:   -brng         Enables/disables blocked RNG (fast coherent PT).",
15459     __FILE__, VRenderParams, group);
15460   theCommands.Add("vstatprofiler",
15461     "\n vstatprofiler [fps|cpu|allLayers|layers|allstructures|structures|groups"
15462     "\n                |allArrays|fillArrays|lineArrays|pointArrays|textArrays"
15463     "\n                |triangles|points|geomMem|textureMem|frameMem"
15464     "\n                |elapsedFrame|cpuFrameAverage|cpuPickingAverage|cpuCullingAverage|cpuDynAverage"
15465     "\n                |cpuFrameMax|cpuPickingMax|cpuCullingMax|cpuDynMax]"
15466     "\n                [-noredraw]"
15467     "\n\t\t: Prints rendering statistics."
15468     "\n\t\t:   If there are some parameters - print corresponding statistic counters values,"
15469     "\n\t\t:   else - print all performance counters set previously."
15470     "\n\t\t:   '-noredraw' Flag to avoid additional redraw call and use already collected values.\n",
15471     __FILE__, VStatProfiler, group);
15472   theCommands.Add ("vplace",
15473             "vplace dx dy"
15474     "\n\t\t: Places the point (in pixels) at the center of the window",
15475     __FILE__, VPlace, group);
15476   theCommands.Add("vxrotate",
15477     "vxrotate",
15478     __FILE__,VXRotate,group);
15479
15480     theCommands.Add("vmanipulator",
15481       "\n    vmanipulator Name [-attach AISObject | -detach | ...]"
15482       "\n    tool to create and manage AIS manipulators."
15483       "\n    Options: "
15484       "\n      '-attach AISObject'                 attach manipulator to AISObject"
15485       "\n      '-adjustPosition {0|center|location|shapeLocation}' adjust position when attaching"
15486       "\n      '-adjustSize     {0|1}'             adjust size when attaching"
15487       "\n      '-enableModes    {0|1}'             enable modes when attaching"
15488       "\n      '-view  {active | [name of view]}'  display manipulator only in defined view,"
15489       "\n                                          by default it is displayed in all views of the current viewer"
15490       "\n      '-detach'                           detach manipulator"
15491       "\n      '-startTransform mouse_x mouse_y' - invoke start of transformation"
15492       "\n      '-transform      mouse_x mouse_y' - invoke transformation"
15493       "\n      '-stopTransform  [abort]'         - invoke stop of transformation"
15494       "\n      '-move x y z'                     - move attached object"
15495       "\n      '-rotate x y z dx dy dz angle'    - rotate attached object"
15496       "\n      '-scale factor'                   - scale attached object"
15497       "\n      '-autoActivate      {0|1}'        - set activation on detection"
15498       "\n      '-followTranslation {0|1}'        - set following translation transform"
15499       "\n      '-followRotation    {0|1}'        - set following rotation transform"
15500       "\n      '-followDragging    {0|1}'        - set following dragging transform"
15501       "\n      '-gap value'                      - set gap between sub-parts"
15502       "\n      '-part axis mode    {0|1}'        - set visual part"
15503       "\n      '-parts axis mode   {0|1}'        - set visual part"
15504       "\n      '-pos x y z [nx ny nz [xx xy xz]' - set position of manipulator"
15505       "\n      '-size value'                     - set size of manipulator"
15506       "\n      '-zoomable {0|1}'                 - set zoom persistence",
15507     __FILE__, VManipulator, group);
15508
15509   theCommands.Add("vselprops",
15510     "\n    vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]"
15511     "\n    Customizes selection and dynamic highlight parameters for the whole interactive context:"
15512     "\n    -autoActivate {0|1}     : disables|enables default computation and activation of global selection mode"
15513     "\n    -autoHighlight {0|1}    : disables|enables automatic highlighting in 3D Viewer"
15514     "\n    -highlightSelected {0|1}: disables|enables highlighting of detected object in selected state"
15515     "\n    -pickStrategy {first|topmost} : defines picking strategy"
15516     "\n                            'first'   to pick first acceptable (default)"
15517     "\n                            'topmost' to pick only topmost (and nothing, if topmost is rejected by filters)"
15518     "\n    -pixTol    value        : sets up pixel tolerance"
15519     "\n    -depthTol {uniform|uniformpx} value : sets tolerance for sorting results by depth"
15520     "\n    -depthTol {sensfactor}  : use sensitive factor for sorting results by depth"
15521     "\n    -preferClosest {0|1}    : sets if depth should take precedence over priority while sorting results"
15522     "\n    -dispMode  dispMode     : sets display mode for highlighting"
15523     "\n    -layer     ZLayer       : sets ZLayer for highlighting"
15524     "\n    -color     {name|r g b} : sets highlight color"
15525     "\n    -transp    value        : sets transparency coefficient for highlight"
15526     "\n    -material  material     : sets highlight material"
15527     "\n    -print                  : prints current state of all mentioned parameters",
15528     __FILE__, VSelectionProperties, group);
15529   theCommands.Add ("vhighlightselected",
15530                    "vhighlightselected [0|1]: alias for vselprops -highlightSelected.\n",
15531                    __FILE__, VSelectionProperties, group);
15532
15533   theCommands.Add ("vseldump",
15534                    "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity}=depth -pickedIndex Index=1"
15535                    "\n\t\t:       [-xrPose base|head=base]"
15536                    "\n\t\t: Generate an image based on detection results:"
15537                    "\n\t\t:   depth       normalized depth values"
15538                    "\n\t\t:   unnormDepth unnormalized depth values"
15539                    "\n\t\t:   object      color of detected object"
15540                    "\n\t\t:   owner       color of detected owner"
15541                    "\n\t\t:   selMode     color of selection mode"
15542                    "\n\t\t:   entity      color of etected entity",
15543                    __FILE__, VDumpSelectionImage, group);
15544
15545   theCommands.Add ("vviewcube",
15546                    "vviewcube name"
15547                    "\n\t\t: Displays interactive view manipualtion object."
15548                    "\n\t\t: Options: "
15549                    "\n\t\t:   -reset                   reset geomertical and visual attributes'"
15550                    "\n\t\t:   -size Size               adapted size of View Cube"
15551                    "\n\t\t:   -boxSize Size            box size"
15552                    "\n\t\t:   -axes  {0|1}             show/hide axes (trihedron)"
15553                    "\n\t\t:   -edges {0|1}             show/hide edges of View Cube"
15554                    "\n\t\t:   -vertices {0|1}          show/hide vertices of View Cube"
15555                    "\n\t\t:   -Yup {0|1} -Zup {0|1}    set Y-up or Z-up view orientation"
15556                    "\n\t\t:   -color Color             color of View Cube"
15557                    "\n\t\t:   -boxColor Color          box color"
15558                    "\n\t\t:   -boxSideColor Color      box sides color"
15559                    "\n\t\t:   -boxEdgeColor Color      box edges color"
15560                    "\n\t\t:   -boxCornerColor Color    box corner color"
15561                    "\n\t\t:   -textColor Color         color of side text of view cube"
15562                    "\n\t\t:   -innerColor Color        inner box color"
15563                    "\n\t\t:   -transparency Value      transparency of object within [0, 1] range"
15564                    "\n\t\t:   -boxTransparency Value   transparency of box    within [0, 1] range"
15565                    "\n\t\t:   -xAxisTextColor Color    color of X axis label"
15566                    "\n\t\t:   -yAxisTextColor Color    color of Y axis label"
15567                    "\n\t\t:   -zAxisTextColor Color    color of Z axis label"
15568                    "\n\t\t:   -font Name               font name"
15569                    "\n\t\t:   -fontHeight Value        font height"
15570                    "\n\t\t:   -boxFacetExtension Value box facet extension"
15571                    "\n\t\t:   -boxEdgeGap Value        gap between box edges and box sides"
15572                    "\n\t\t:   -boxEdgeMinSize Value    minimal box edge size"
15573                    "\n\t\t:   -boxCornerMinSize Value  minimal box corner size"
15574                    "\n\t\t:   -axesPadding Value       padding between box and arrows"
15575                    "\n\t\t:   -roundRadius Value       relative radius of corners of sides within [0.0, 0.5] range"
15576                    "\n\t\t:   -axesRadius Value        radius of axes of the trihedron"
15577                    "\n\t\t:   -axesConeRadius Value    radius of the cone (arrow) of the trihedron"
15578                    "\n\t\t:   -axesSphereRadius Value  radius of the sphere (central point) of trihedron"
15579                    "\n\t\t:   -fixedanimation {0|1}    uninterruptible animation loop"
15580                    "\n\t\t:   -duration Seconds        animation duration in seconds",
15581     __FILE__, VViewCube, group);
15582
15583   theCommands.Add("vcolorconvert" ,
15584                   "vcolorconvert {from|to} type C1 C2 C2"
15585                   "\n\t\t: vcolorconvert from type C1 C2 C2: Converts color from specified color space to linear RGB"
15586                   "\n\t\t: vcolorconvert to type R G B: Converts linear RGB color to specified color space"
15587                   "\n\t\t: type can be sRGB, HLS, Lab, or Lch",
15588                   __FILE__,VColorConvert,group);
15589   theCommands.Add("vcolordiff" ,
15590                   "vcolordiff R1 G1 B1 R2 G2 B2: returns CIEDE2000 color difference between two RGB colors",
15591                   __FILE__,VColorDiff,group);
15592   theCommands.Add("vselbvhbuild",
15593                   "vselbvhbuild [{0|1}] [-nbThreads value] [-wait]"
15594                   "\n\t\t: Turns on/off prebuilding of BVH within background thread(s)"
15595                   "\n\t\t:   -nbThreads   number of threads, 1 by default; if < 1 then used (NbLogicalProcessors - 1)"
15596                   "\n\t\t:   -wait        waits for building all of BVH",
15597                   __FILE__,VSelBvhBuild,group);
15598 }