0a37eb4eef863d90be4d88e03b54b51e52fe2d4f
[occt.git] / src / ViewerTest / ViewerTest_ViewerCommands.cxx
1 // Created on: 1998-09-01
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #if defined(_WIN32)
18   #include <windows.h>
19 #endif
20
21 #include <ViewerTest.hxx>
22
23 #include <AIS_AnimationCamera.hxx>
24 #include <AIS_AnimationObject.hxx>
25 #include <AIS_Axis.hxx>
26 #include <AIS_CameraFrustum.hxx>
27 #include <AIS_ColorScale.hxx>
28 #include <AIS_InteractiveContext.hxx>
29 #include <AIS_LightSource.hxx>
30 #include <AIS_ListOfInteractive.hxx>
31 #include <AIS_ListIteratorOfListOfInteractive.hxx>
32 #include <AIS_Manipulator.hxx>
33 #include <AIS_ViewCube.hxx>
34 #include <AIS_Shape.hxx>
35 #include <AIS_Point.hxx>
36 #include <Aspect_DisplayConnection.hxx>
37 #include <Aspect_Grid.hxx>
38 #include <Aspect_TypeOfLine.hxx>
39 #include <Draw.hxx>
40 #include <Draw_Appli.hxx>
41 #include <Draw_Interpretor.hxx>
42 #include <Draw_ProgressIndicator.hxx>
43 #include <gp_Dir.hxx>
44 #include <gp_Pln.hxx>
45 #include <gp_Pnt.hxx>
46 #include <Geom_Axis2Placement.hxx>
47 #include <Geom_CartesianPoint.hxx>
48 #include <Graphic3d_ArrayOfPolylines.hxx>
49 #include <Graphic3d_AspectFillArea3d.hxx>
50 #include <Graphic3d_AspectMarker3d.hxx>
51 #include <Graphic3d_ClipPlane.hxx>
52 #include <Graphic3d_CubeMapPacked.hxx>
53 #include <Graphic3d_CubeMapSeparate.hxx>
54 #include <Graphic3d_GraduatedTrihedron.hxx>
55 #include <Graphic3d_GraphicDriver.hxx>
56 #include <Graphic3d_GraphicDriverFactory.hxx>
57 #include <Graphic3d_NameOfTextureEnv.hxx>
58 #include <Graphic3d_Texture2Dmanual.hxx>
59 #include <Graphic3d_TextureEnv.hxx>
60 #include <Graphic3d_TextureParams.hxx>
61 #include <Graphic3d_TypeOfTextureFilter.hxx>
62 #include <Image_AlienPixMap.hxx>
63 #include <Image_Diff.hxx>
64 #include <Image_VideoRecorder.hxx>
65 #include <Message.hxx>
66 #include <Message_ProgressScope.hxx>
67 #include <Message_ProgressRange.hxx>
68 #include <NCollection_DataMap.hxx>
69 #include <NCollection_List.hxx>
70 #include <NCollection_LocalArray.hxx>
71 #include <NCollection_Vector.hxx>
72 #include <OSD.hxx>
73 #include <OSD_Parallel.hxx>
74 #include <OSD_Timer.hxx>
75 #include <Prs3d_ShadingAspect.hxx>
76 #include <Prs3d_DatumAspect.hxx>
77 #include <Prs3d_Drawer.hxx>
78 #include <Prs3d_LineAspect.hxx>
79 #include <Prs3d_Text.hxx>
80 #include <Select3D_SensitivePrimitiveArray.hxx>
81 #include <TColStd_HSequenceOfAsciiString.hxx>
82 #include <TColStd_SequenceOfInteger.hxx>
83 #include <TColStd_HSequenceOfReal.hxx>
84 #include <TColgp_Array1OfPnt2d.hxx>
85 #include <TColStd_MapOfAsciiString.hxx>
86 #include <ViewerTest_AutoUpdater.hxx>
87 #include <ViewerTest_ContinuousRedrawer.hxx>
88 #include <ViewerTest_EventManager.hxx>
89 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
90 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
91 #include <ViewerTest_CmdParser.hxx>
92 #include <ViewerTest_V3dView.hxx>
93 #include <V3d_AmbientLight.hxx>
94 #include <V3d_DirectionalLight.hxx>
95 #include <V3d_PositionalLight.hxx>
96 #include <V3d_SpotLight.hxx>
97 #include <V3d_Trihedron.hxx>
98 #include <V3d_Viewer.hxx>
99 #include <UnitsAPI.hxx>
100
101 #include <tcl.h>
102
103 #include <cstdlib>
104
105 #if defined(_WIN32)
106   #include <WNT_WClass.hxx>
107   #include <WNT_Window.hxx>
108   #include <WNT_HIDSpaceMouse.hxx>
109 #elif defined(HAVE_XLIB)
110   #include <Xw_Window.hxx>
111   #include <X11/Xlib.h>
112   #include <X11/Xutil.h>
113 #elif defined(__APPLE__)
114   #include <Cocoa_Window.hxx>
115 #else
116   #include <Aspect_NeutralWindow.hxx>
117 #endif
118
119 //==============================================================================
120 //  VIEWER GLOBAL VARIABLES
121 //==============================================================================
122
123 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
124 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
125
126 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
127 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
128
129 #if defined(_WIN32)
130 typedef WNT_Window ViewerTest_Window;
131 #elif defined(HAVE_XLIB)
132 typedef Xw_Window ViewerTest_Window;
133 static void VProcessEvents(ClientData,int);
134 #elif defined(__APPLE__)
135 typedef Cocoa_Window ViewerTest_Window;
136 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
137 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
138 #else
139 typedef Aspect_NeutralWindow ViewerTest_Window;
140 #endif
141
142 static Handle(ViewerTest_Window)& VT_GetWindow()
143 {
144   static Handle(ViewerTest_Window) aWindow;
145   return aWindow;
146 }
147
148 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
149 {
150   static Handle(Aspect_DisplayConnection) aDisplayConnection;
151   return aDisplayConnection;
152 }
153
154 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
155 {
156   GetDisplayConnection() = theDisplayConnection;
157 }
158
159 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
160 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
161 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
162
163 static void OSWindowSetup();
164
165 static struct
166 {
167   Quantity_Color FlatColor;
168   Quantity_Color GradientColor1;
169   Quantity_Color GradientColor2;
170   Aspect_GradientFillMethod FillMethod;
171 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
172
173 //==============================================================================
174 //  EVENT GLOBAL VARIABLES
175 //==============================================================================
176
177 Standard_Boolean TheIsAnimating = Standard_False;
178
179 namespace
180 {
181
182   //! Checks if some set is a subset of other set
183   //! @tparam TheSuperSet the type of the superset
184   //! @tparam TheSubSet the type of the subset
185   //! @param theSuperSet the superset
186   //! @param theSubSet the subset to be checked
187   //! @return true if the superset includes subset, or false otherwise
188   template <typename TheSuperSet, typename TheSubSet>
189   static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
190   {
191     return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
192   }
193
194   //! A variable set of keys for command-line options.
195   //! It includes a set of mandatory keys and a set of all possible keys.
196   class CommandOptionKeyVariableSet
197   {
198   public:
199     //! Default constructor
200     CommandOptionKeyVariableSet()
201     {
202     }
203
204     //! Constructor
205     //! @param theMandatoryKeySet the set of the mandatory option keys
206     //! @param theAdditionalKeySet the set of additional options that could be omitted
207     CommandOptionKeyVariableSet (
208       const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
209       const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
210     : myMandatoryKeySet (theMandatoryKeySet)
211     {
212       std::set_union (theMandatoryKeySet.begin(),
213                       theMandatoryKeySet.end(),
214                       theAdditionalKeySet.begin(),
215                       theAdditionalKeySet.end(),
216                       std::inserter (myFullKeySet, myFullKeySet.begin()));
217     }
218
219     //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
220     //! and be contained in the full key set)
221     //! @param theCheckedKeySet the set of option keys to be checked
222     bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
223     {
224       return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
225     }
226
227   private:
228     //! A set of mandatory command-line option keys
229     ViewerTest_CommandOptionKeySet myMandatoryKeySet;
230
231     //! A full set of command-line option keys (includes mandatory and additional option keys)
232     ViewerTest_CommandOptionKeySet myFullKeySet;
233   };
234
235   //! Gets some code by its name
236   //! @tparam TheCode the type of a code to be found
237   //! @param theCodeNameMap the map from code names to codes
238   //! @param theCodeName the name of a code to be found
239   //! @param theCode the code to be found
240   //! @return true if a code is found, or false otherwise
241   template <typename TheCode>
242   static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
243                                  TCollection_AsciiString                           theCodeName,
244                                  TheCode&                                          theCode)
245   {
246     theCodeName.LowerCase();
247     const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
248       theCodeName);
249     if (aCodeIterator == theCodeNameMap.end())
250     {
251       return false;
252     }
253     theCode = aCodeIterator->second;
254     return true;
255   }
256
257   // Defines possible commands related to background changing
258   enum BackgroundCommand
259   {
260     BackgroundCommand_Main,              //!< The main command that manages other commands through options
261     BackgroundCommand_Image,             //!< Sets an image as a background
262     BackgroundCommand_ImageMode,         //!< Changes a background image mode
263     BackgroundCommand_Gradient,          //!< Sets a gradient as a background
264     BackgroundCommand_GradientMode,      //!< Changes a background gradient mode
265     BackgroundCommand_Color,             //!< Fills background with a specified color
266     BackgroundCommand_Default            //!< Sets the background default color or gradient
267   };
268
269   //! Map from background command names to its codes
270   typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
271
272   //! Creates a map from background command names to its codes
273   //! @return a map from background command names to its codes
274   static BackgroundCommandNameMap createBackgroundCommandNameMap()
275   {
276     BackgroundCommandNameMap aBackgroundCommandNameMap;
277     aBackgroundCommandNameMap["vbackground"]      = BackgroundCommand_Main;
278     aBackgroundCommandNameMap["vsetbg"]           = BackgroundCommand_Image;
279     aBackgroundCommandNameMap["vsetbgmode"]       = BackgroundCommand_ImageMode;
280     aBackgroundCommandNameMap["vsetgradientbg"]   = BackgroundCommand_Gradient;
281     aBackgroundCommandNameMap["vsetgrbgmode"]     = BackgroundCommand_GradientMode;
282     aBackgroundCommandNameMap["vsetcolorbg"]      = BackgroundCommand_Color;
283     aBackgroundCommandNameMap["vsetdefaultbg"]    = BackgroundCommand_Default;
284     return aBackgroundCommandNameMap;
285   }
286
287   //! Gets a background command by its name
288   //! @param theBackgroundCommandName the name of the background command
289   //! @param theBackgroundCommand the background command to be found
290   //! @return true if a background command is found, or false otherwise
291   static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
292                                           BackgroundCommand&             theBackgroundCommand)
293   {
294     static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
295     return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
296   }
297
298   //! Map from background image fill method names to its codes
299   typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
300
301   //! Creates a map from background image fill method names to its codes
302   //! @return a map from background image fill method names to its codes
303   static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
304   {
305     BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
306     aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
307     aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
308     aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
309     aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
310     return aBackgroundImageFillMethodNameMap;
311   }
312
313   //! Gets a background image fill method by its name
314   //! @param theBackgroundImageFillMethodName the name of the background image fill method
315   //! @param theBackgroundImageFillMethod the background image fill method to be found
316   //! @return true if a background image fill method is found, or false otherwise
317   static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
318                                                   Aspect_FillMethod&             theBackgroundImageFillMethod)
319   {
320     static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
321       createBackgroundImageFillMethodNameMap();
322     return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
323                               theBackgroundImageFillMethodName,
324                               theBackgroundImageFillMethod);
325   }
326
327   //! Map from background gradient fill method names to its codes
328   typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
329
330   //! Creates a map from background gradient fill method names to its codes
331   //! @return a map from background gradient fill method names to its codes
332   static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
333   {
334     BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
335     aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
336     aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
337     aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
338     aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
339     aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
340     aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
341     aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
342     aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
343     aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
344     aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
345     aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
346     aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
347     aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
348     return aBackgroundGradientFillMethodNameMap;
349   }
350
351   //! Gets a gradient fill method by its name
352   //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
353   //! @param theBackgroundGradientFillMethod the gradient fill method to be found
354   //! @return true if a gradient fill method is found, or false otherwise
355   static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
356                                                      Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
357   {
358     static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
359       createBackgroundGradientFillMethodNameMap();
360     return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
361                               theBackgroundGradientFillMethodName,
362                               theBackgroundGradientFillMethod);
363   }
364
365   //! Changes the background in accordance with passed command line options
366   class BackgroundChanger
367   {
368   public:
369     //! Constructor. Prepares the command parser
370     BackgroundChanger()
371     {
372       prepareCommandParser();
373     }
374
375     //! Processes the command line and changes the background
376     //! @param theDrawInterpretor the interpreter of the Draw Harness application
377     //! @param theNumberOfCommandLineArguments the number of passed command line arguments
378     //! @param theCommandLineArguments the array of command line arguments
379     bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
380                              const Standard_Integer   theNumberOfCommandLineArguments,
381                              const char* const* const theCommandLineArguments)
382     {
383       const char* const aBackgroundCommandName = theCommandLineArguments[0];
384       BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
385       if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
386       {
387         return false;
388       }
389       addCommandDescription (aBackgroundCommand);
390       myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
391       return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
392     }
393
394   private:
395     //! The type of functions that are able to set gradient background filling
396     typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
397                                       const Quantity_Color& /* theColor2 */,
398                                       const Aspect_GradientFillMethod /* theGradientMode */);
399
400     //! The type of functions that are able to fill a background with a specific color
401     typedef void SetColorFunction (const Quantity_Color& /* theColor */);
402
403     //! the command parser used to parse command line options and its arguments
404     ViewerTest_CmdParser myCommandParser;
405
406     //! the option key for the command that sets an image as a background
407     ViewerTest_CommandOptionKey myImageOptionKey;
408
409     //! the option key for the command that sets a background image fill type
410     ViewerTest_CommandOptionKey myImageModeOptionKey;
411
412     //! the option key for the command that sets a gradient filling for the background
413     ViewerTest_CommandOptionKey myGradientOptionKey;
414
415     //! the option key for the command that sets a background gradient filling method
416     ViewerTest_CommandOptionKey myGradientModeOptionKey;
417
418     //! the option key for the command that fills background with a specific color
419     ViewerTest_CommandOptionKey myColorOptionKey;
420
421     //! the option key for the command that sets default background gradient or color
422     ViewerTest_CommandOptionKey myDefaultOptionKey;
423
424     //! the option key for the command that sets an environment cubemap as a background
425     ViewerTest_CommandOptionKey myCubeMapOptionKey;
426
427     //! the option key for the command that defines order of tiles in one image packed cubemap
428     ViewerTest_CommandOptionKey myCubeMapOrderOptionKey;
429
430     //! the option key for the command that sets inversion of Z axis for background cubemap
431     ViewerTest_CommandOptionKey myCubeMapInvertedZOptionKey;
432
433     //! the option key for the command that allows skip IBL map generation
434     ViewerTest_CommandOptionKey myCubeMapDoNotGenPBREnvOptionKey;
435
436     //! the variable set of options that are allowed for the old scenario (without any option passed)
437     CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
438
439     //! the variable set of options that are allowed for setting an environment cubemap as background
440     CommandOptionKeyVariableSet myCubeMapOptionVariableSet;
441
442     //! the variable set of options that are allowed for setting an image as a background
443     CommandOptionKeyVariableSet myImageOptionVariableSet;
444
445     //! the variable set of options that are allowed for setting a background image fill type
446     CommandOptionKeyVariableSet myImageModeOptionVariableSet;
447
448     //! the variable set of options that are allowed for setting a gradient filling for the background
449     CommandOptionKeyVariableSet myGradientOptionVariableSet;
450
451     //! the variable set of options that are allowed for setting a background gradient filling method
452     CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
453
454     //! the variable set of options that are allowed for filling a background with a specific color
455     CommandOptionKeyVariableSet myColorOptionVariableSet;
456
457     //! the variable set of options that are allowed for setting a default background gradient
458     CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
459
460     //! the variable set of options that are allowed for setting a default background color
461     CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
462
463     //! the variable set of options that are allowed for printing help
464     CommandOptionKeyVariableSet myHelpOptionVariableSet;
465
466     //! Adds options to command parser
467     void addOptionsToCommandParser()
468     {
469       myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
470                                                     "filename of image used as background");
471       myImageModeOptionKey = myCommandParser.AddOption (
472         "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
473       myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
474                                                        "sets background gradient starting and ending colors");
475       myGradientModeOptionKey =
476         myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
477                                    "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
478                                    "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
479       myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
480       myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
481
482       myCubeMapOptionKey           = myCommandParser.AddOption ("cubemap|cmap|cm", "background cubemap");
483       myCubeMapOrderOptionKey      = myCommandParser.AddOption ("order|o", "order of sides in one image packed cubemap");
484       myCubeMapInvertedZOptionKey = myCommandParser.AddOption (
485         "invertedz|invz|iz", "whether Z axis is inverted or not during background cubemap rendering");
486       myCubeMapDoNotGenPBREnvOptionKey = myCommandParser.AddOption ("nopbrenv", "whether IBL map generation should be skipped");
487     }
488
489     //! Creates option sets used to determine if a passed option set is valid or not
490     void createOptionSets()
491     {
492       ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
493       anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
494       myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
495
496       ViewerTest_CommandOptionKeySet aCubeMapOptionSet;
497       aCubeMapOptionSet.insert (myCubeMapOptionKey);
498       ViewerTest_CommandOptionKeySet aCubeMapAdditionalOptionKeySet;
499       aCubeMapAdditionalOptionKeySet.insert (myCubeMapInvertedZOptionKey);
500       aCubeMapAdditionalOptionKeySet.insert (myCubeMapDoNotGenPBREnvOptionKey);
501       aCubeMapAdditionalOptionKeySet.insert (myCubeMapOrderOptionKey);
502       myCubeMapOptionVariableSet     = CommandOptionKeyVariableSet (aCubeMapOptionSet, aCubeMapAdditionalOptionKeySet);
503
504       ViewerTest_CommandOptionKeySet anImageOptionSet;
505       anImageOptionSet.insert (myImageOptionKey);
506       ViewerTest_CommandOptionKeySet anImageModeOptionSet;
507       anImageModeOptionSet.insert (myImageModeOptionKey);
508       myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
509       myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
510
511       ViewerTest_CommandOptionKeySet aGradientOptionSet;
512       aGradientOptionSet.insert (myGradientOptionKey);
513       ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
514       aGradientModeOptionSet.insert (myGradientModeOptionKey);
515       myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
516       myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
517
518       ViewerTest_CommandOptionKeySet aColorOptionSet;
519       aColorOptionSet.insert (myColorOptionKey);
520       myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
521
522       aGradientOptionSet.insert (myDefaultOptionKey);
523       myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
524       aColorOptionSet.insert (myDefaultOptionKey);
525       myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
526
527       ViewerTest_CommandOptionKeySet aHelpOptionSet;
528       aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
529       myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
530     }
531
532     //! Prepares the command parser. Adds options and creates option sets used to determine
533     //! if a passed option set is valid or not
534     void prepareCommandParser()
535     {
536       addOptionsToCommandParser();
537       createOptionSets();
538     }
539
540     //! Adds a command description to the command parser
541     //! @param theBackgroundCommand the key of the command which description is added to the command parser
542     void addCommandDescription (const BackgroundCommand theBackgroundCommand)
543     {
544       std::string aDescription;
545       bool        isMainCommand = false;
546       switch (theBackgroundCommand)
547       {
548         case BackgroundCommand_Main:
549           aDescription  = "Command: vbackground (changes background or some background settings)";
550           isMainCommand = true;
551           break;
552         case BackgroundCommand_Image:
553           aDescription = "Command: vsetbg (loads image as a background)";
554           break;
555         case BackgroundCommand_ImageMode:
556           aDescription = "Command: vsetbgmode (changes background fill type)";
557           break;
558         case BackgroundCommand_Gradient:
559           aDescription = "Command: vsetgradientbg (mounts gradient background)";
560           break;
561         case BackgroundCommand_GradientMode:
562           aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
563           break;
564         case BackgroundCommand_Color:
565           aDescription = "Command: vsetcolorbg (sets color background)";
566           break;
567         case BackgroundCommand_Default:
568           aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
569           break;
570         default:
571           return;
572       }
573       if (!isMainCommand)
574       {
575         aDescription += "\nThis command is obsolete. Use vbackground instead.";
576       }
577       myCommandParser.SetDescription (aDescription);
578     }
579
580     //! Check if a viewer is needed to be initialized
581     //! @param theBackgroundCommand the key of the command that changes the background
582     //! @return true if processing was successful, or false otherwise
583     bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
584     {
585       const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
586       const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
587       const bool                           aViewerIsNotNeeded =
588         (theBackgroundCommand == BackgroundCommand_Default)
589         || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
590         || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
591         || myHelpOptionVariableSet.IsInSet (aUsedOptions);
592       return !aViewerIsNotNeeded;
593     }
594
595     //! Check if a viewer is initialized
596     //! @param theBackgroundCommandName the name of the command that changes the background
597     //! @param theDrawInterpretor the interpreter of the Draw Harness application
598     //! @return true if a viewer is initialized, or false otherwise
599     static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
600                                           Draw_Interpretor& theDrawInterpretor)
601     {
602       const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
603       if (anAISContext.IsNull())
604       {
605         theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
606         return false;
607       }
608       return true;
609     }
610
611     //! Processes command options
612     //! @param theBackgroundCommandName the name of the command that changes the background
613     //! @param theBackgroundCommand the key of the command that changes the background
614     //! @param theDrawInterpretor the interpreter of the Draw Harness application
615     //! @return true if processing was successful, or false otherwise
616     bool processCommandOptions (const char* const       theBackgroundCommandName,
617                                 const BackgroundCommand theBackgroundCommand,
618                                 Draw_Interpretor&       theDrawInterpretor) const
619     {
620       if (myCommandParser.HasNoOption())
621       {
622         return printHelp (theBackgroundCommandName, theDrawInterpretor);
623       }
624       if (checkViewerIsNeeded (theBackgroundCommand)
625           && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
626       {
627         return false;
628       }
629       if (myCommandParser.HasOnlyUnnamedOption())
630       {
631         return processUnnamedOption (theBackgroundCommand);
632       }
633       return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
634     }
635
636     //! Processes the unnamed option
637     //! @param theBackgroundCommand the key of the command that changes the background
638     //! @return true if processing was successful, or false otherwise
639     bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
640     {
641       switch (theBackgroundCommand)
642       {
643         case BackgroundCommand_Main:
644           return false;
645         case BackgroundCommand_Image:
646           return processImageUnnamedOption();
647         case BackgroundCommand_ImageMode:
648           return processImageModeUnnamedOption();
649         case BackgroundCommand_Gradient:
650           return processGradientUnnamedOption();
651         case BackgroundCommand_GradientMode:
652           return processGradientModeUnnamedOption();
653         case BackgroundCommand_Color:
654           return processColorUnnamedOption();
655         case BackgroundCommand_Default:
656           return processDefaultUnnamedOption();
657         default:
658           return false;
659       }
660     }
661
662     //! Processes the image unnamed option
663     //! @return true if processing was successful, or false otherwise
664     bool processImageUnnamedOption() const
665     {
666       const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
667         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
668       if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
669       {
670         return false;
671       }
672       std::string anImageFileName;
673       if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
674       {
675         return false;
676       }
677       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
678       if (aNumberOfImageUnnamedOptionArguments == 2)
679       {
680         std::string anImageModeString;
681         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
682         {
683           return false;
684         }
685         if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
686         {
687           return false;
688         }
689       }
690       setImage (anImageFileName.c_str(), anImageMode);
691       return true;
692     }
693
694     //! Processes the image mode unnamed option
695     //! @return true if processing was successful, or false otherwise
696     bool processImageModeUnnamedOption() const
697     {
698       return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
699     }
700
701     //! Processes the gradient unnamed option
702     //! @param theSetGradient the function used to set a background gradient filling
703     //! @return true if processing was successful, or false otherwise
704     bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
705     {
706       const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
707         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
708       if (aNumberOfGradientUnnamedOptionArguments < 2)
709       {
710         return false;
711       }
712
713       Standard_Integer anArgumentIndex = 0;
714       Quantity_Color   aColor1;
715       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
716       {
717         return false;
718       }
719       if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
720       {
721         return false;
722       }
723
724       Quantity_Color aColor2;
725       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
726       {
727         return false;
728       }
729       if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
730       {
731         return false;
732       }
733
734       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
735       if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
736       {
737         std::string anGradientModeString;
738
739         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
740                                   anArgumentIndex,
741                                   anGradientModeString))
742         {
743           return false;
744         }
745         if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
746         {
747           return false;
748         }
749         ++anArgumentIndex;
750       }
751       if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
752       {
753         return false;
754       }
755       theSetGradient (aColor1, aColor2, aGradientMode);
756       return true;
757     }
758
759     //! Processes the gradient mode unnamed option
760     //! @return true if processing was successful, or false otherwise
761     bool processGradientModeUnnamedOption() const
762     {
763       return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
764     }
765
766     //! Processes the color unnamed option
767     //! @param theSetColor the function used to set a background color
768     //! @return true if processing was successful, or false otherwise
769     bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
770     {
771       return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
772     }
773
774     //! Processes the default back unnamed option
775     //! @return true if processing was successful, or false otherwise
776     bool processDefaultUnnamedOption() const
777     {
778       if (processGradientUnnamedOption (setDefaultGradient))
779       {
780         return true;
781       }
782       return processColorUnnamedOption (setDefaultColor);
783     }
784
785     //! Processes named options
786     //! @param theBackgroundCommandName the name of the command that changes the background
787     //! @param theBackgroundCommand the key of the command that changes the background
788     //! @param theDrawInterpretor the interpreter of the Draw Harness application
789     //! @return true if processing was successful, or false otherwise
790     bool processNamedOptions (const char* const       theBackgroundCommandName,
791                               const BackgroundCommand theBackgroundCommand,
792                               Draw_Interpretor&       theDrawInterpretor) const
793     {
794       const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
795       const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
796       if (myCubeMapOptionVariableSet.IsInSet (aUsedOptions) && isMain)
797       {
798         return processCubeMapOptionSet();
799       }
800       if (myImageOptionVariableSet.IsInSet (aUsedOptions)
801           && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
802       {
803         return processImageOptionSet();
804       }
805       if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
806           && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
807       {
808         return processImageModeOptionSet();
809       }
810       if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
811           && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
812       {
813         return processGradientOptionSet();
814       }
815       if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
816           && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
817       {
818         return processGradientModeOptionSet();
819       }
820       if (myColorOptionVariableSet.IsInSet (aUsedOptions)
821           && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
822       {
823         return processColorOptionSet();
824       }
825       if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
826           || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
827               && (theBackgroundCommand == BackgroundCommand_Default)))
828       {
829         return processDefaultGradientOptionSet();
830       }
831       if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
832           || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
833       {
834         return processDefaultColorOptionSet();
835       }
836       if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
837       {
838         return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
839       }
840       return false;
841     }
842
843     //! Process the cubemap option set in named and unnamed case.
844     //! @return true if processing was successful, or false otherwise
845     bool processCubeMapOptionSet() const
846     {
847       NCollection_Array1<TCollection_AsciiString> aFilePaths;
848
849       if (!processCubeMapOptions (aFilePaths))
850       {
851         return false;
852       }
853
854       Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
855
856       if (myCommandParser.HasOption (myCubeMapOrderOptionKey))
857       {
858         if (!processCubeMapOrderOptions (anOrder))
859         {
860           return false;
861         }
862       }
863
864       bool aZIsInverted = false;
865       if (myCommandParser.HasOption (myCubeMapInvertedZOptionKey))
866       {
867         if (!processCubeMapInvertedZOptionSet())
868         {
869           return false;
870         }
871         aZIsInverted = true;
872       }
873
874       bool aToGenPBREnv = true;
875       if (myCommandParser.HasOption (myCubeMapDoNotGenPBREnvOptionKey))
876       {
877         if (!processCubeMapDoNotGenPBREnvOptionSet())
878         {
879           return false;
880         }
881         aToGenPBREnv = false;
882       }
883
884       setCubeMap (aFilePaths, anOrder.Validated(), aZIsInverted, aToGenPBREnv);
885       return true;
886     }
887
888     //! Processes the image option set
889     //! @return true if processing was successful, or false otherwise
890     bool processImageOptionSet() const
891     {
892       std::string anImageFileName;
893       if (!processImageOption (anImageFileName))
894       {
895         return false;
896       }
897       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
898       if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
899       {
900         return false;
901       }
902       setImage (anImageFileName.c_str(), anImageMode);
903       return true;
904     }
905
906     //! Processes the image mode option set
907     //! @return true if processing was successful, or false otherwise
908     bool processImageModeOptionSet() const
909     {
910       return processImageModeOptionSet (myImageModeOptionKey);
911     }
912
913     //! Processes the image mode option set
914     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
915     //! @return true if processing was successful, or false otherwise
916     bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
917     {
918       Aspect_FillMethod anImageMode = Aspect_FM_NONE;
919       if (!processImageModeOption (theImageModeOptionKey, anImageMode))
920       {
921         return false;
922       }
923       setImageMode (anImageMode);
924       return true;
925     }
926
927     //! Processes the gradient option set
928     //! @param theSetGradient the function used to set a background gradient filling
929     //! @return true if processing was successful, or false otherwise
930     bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
931     {
932       Quantity_Color aColor1;
933       Quantity_Color aColor2;
934       if (!processGradientOption (aColor1, aColor2))
935       {
936         return false;
937       }
938       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
939       if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
940       {
941         return false;
942       }
943       theSetGradient (aColor1, aColor2, aGradientMode);
944       return true;
945     }
946
947     //! Processes the gradient mode option set
948     //! @return true if processing was successful, or false otherwise
949     bool processGradientModeOptionSet() const
950     {
951       return processGradientModeOptionSet (myGradientModeOptionKey);
952     }
953
954     //! Processes the gradient mode option set
955     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
956     //! @return true if processing was successful, or false otherwise
957     bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
958     {
959       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
960       if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
961       {
962         return false;
963       }
964       setGradientMode (aGradientMode);
965       return true;
966     }
967
968     //! Processes the color option set
969     //! @param theSetColor the function used to set a background color
970     //! @return true if processing was successful, or false otherwise
971     bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
972     {
973       return processColorOptionSet (myColorOptionKey, theSetColor);
974     }
975
976     //! Processes the default color option set
977     //! @return true if processing was successful, or false otherwise
978     bool processDefaultGradientOptionSet() const
979     {
980       return processGradientOptionSet (setDefaultGradient);
981     }
982
983     //! Processes the default gradient option set
984     //! @return true if processing was successful, or false otherwise
985     bool processDefaultColorOptionSet() const
986     {
987       return processColorOptionSet (setDefaultColor);
988     }
989
990     //! Processes the color option set
991     //! @param theColorOptionKey the key of the option that is interpreted as a color option
992     //! @param theSetColor the function used to set a background color
993     //! @return true if processing was successful, or false otherwise
994     bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
995                                 SetColorFunction* const           theSetColor = setColor) const
996     {
997       Quantity_Color aColor;
998       if (!processColorOption (theColorOptionKey, aColor))
999       {
1000         return false;
1001       }
1002       theSetColor (aColor);
1003       return true;
1004     }
1005
1006     //! Processes the help option set
1007     //! @param theBackgroundCommandName the name of the command that changes the background
1008     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1009     //! @return true if processing was successful, or false otherwise
1010     bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
1011     {
1012       const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1013         ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
1014       if (aNumberOfHelpOptionArguments != 0)
1015       {
1016         return false;
1017       }
1018       return printHelp (theBackgroundCommandName, theDrawInterpretor);
1019     }
1020
1021     //! Processes the cubemap option
1022     //! @param theFilePaths the array of filenames of cubemap sides
1023     //! @return true if processing was successful, or false otherwise
1024     bool processCubeMapOptions (NCollection_Array1<TCollection_AsciiString> &theFilePaths) const
1025     {
1026       const Standard_Integer aNumberOfCubeMapOptionArguments = myCommandParser.GetNumberOfOptionArguments (myCubeMapOptionKey);
1027
1028       if (aNumberOfCubeMapOptionArguments != 1
1029        && aNumberOfCubeMapOptionArguments != 6)
1030       {
1031         return false;
1032       }
1033
1034       theFilePaths.Resize(0, aNumberOfCubeMapOptionArguments - 1, Standard_False);
1035
1036       for (int i = 0; i < aNumberOfCubeMapOptionArguments; ++i)
1037       {
1038         std::string aCubeMapFileName;
1039         if (!myCommandParser.Arg (myCubeMapOptionKey, i, aCubeMapFileName))
1040         {
1041           return false;
1042         }
1043         theFilePaths[i] = aCubeMapFileName.c_str();
1044       }
1045
1046       return true;
1047     }
1048
1049     //! Processes the inverted z cubemap option
1050     //! @return true if processing was successful, or false otherwise
1051     bool processCubeMapInvertedZOptionSet () const
1052     {
1053       const Standard_Integer aNumberOfCubeMapZInversionOptionArguments =
1054         myCommandParser.GetNumberOfOptionArguments (myCubeMapInvertedZOptionKey);
1055
1056       if (aNumberOfCubeMapZInversionOptionArguments != 0)
1057       {
1058         return false;
1059       }
1060
1061       return true;
1062     }
1063
1064     //! Processes the option allowing to skip IBM maps generation
1065     //! @return true if processing was successful, or false otherwise
1066     bool processCubeMapDoNotGenPBREnvOptionSet() const
1067     {
1068       const Standard_Integer aNumberOfCubeMapDoNotGenPBREnvOptionArguments =
1069         myCommandParser.GetNumberOfOptionArguments(myCubeMapDoNotGenPBREnvOptionKey);
1070
1071       if (aNumberOfCubeMapDoNotGenPBREnvOptionArguments != 0)
1072       {
1073         return false;
1074       }
1075
1076       return true;
1077     }
1078
1079     //! Processes the tiles order option
1080     //! @param theOrder the array of indexes if cubemap sides in tile grid
1081     //! @return true if processing was successful, or false otherwise
1082     bool processCubeMapOrderOptions (Graphic3d_CubeMapOrder& theOrder) const
1083     {
1084       const Standard_Integer aNumberOfCubeMapOrderOptionArguments = myCommandParser.GetNumberOfOptionArguments(
1085         myCubeMapOrderOptionKey);
1086
1087       if (aNumberOfCubeMapOrderOptionArguments != 6)
1088       {
1089         return false;
1090       }
1091
1092
1093       for (unsigned int i = 0; i < 6; ++i)
1094       {
1095         std::string anOrderItem;
1096         if (!myCommandParser.Arg (myCubeMapOrderOptionKey, i, anOrderItem)) 
1097         {
1098           return false;
1099         }
1100
1101         theOrder.Set (Graphic3d_CubeMapSide (i),
1102                       static_cast<unsigned char> (Draw::Atoi (anOrderItem.c_str())));
1103       }
1104
1105       return theOrder.IsValid();
1106     }
1107
1108     //! Processes the image option
1109     //! @param theImageFileName the filename of the image to be used as a background
1110     //! @return true if processing was successful, or false otherwise
1111     bool processImageOption (std::string& theImageFileName) const
1112     {
1113       const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1114         myImageOptionKey);
1115       if (aNumberOfImageOptionArguments != 1)
1116       {
1117         return false;
1118       }
1119       std::string anImageFileName;
1120       if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
1121       {
1122         return false;
1123       }
1124       theImageFileName = anImageFileName;
1125       return true;
1126     }
1127
1128     //! Processes the image mode option
1129     //! @param theImageMode the fill type used for a background image
1130     //! @return true if processing was successful, or false otherwise
1131     bool processImageModeOption (Aspect_FillMethod& theImageMode) const
1132     {
1133       return processImageModeOption (myImageModeOptionKey, theImageMode);
1134     }
1135
1136     //! Processes the image mode option
1137     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
1138     //! @param theImageMode the fill type used for a background image
1139     //! @return true if processing was successful, or false otherwise
1140     bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
1141                                  Aspect_FillMethod&                theImageMode) const
1142     {
1143       return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
1144     }
1145
1146     //! Processes the gradient option
1147     //! @param theColor1 the gradient starting color
1148     //! @param theColor2 the gradient ending color
1149     //! @return true if processing was successful, or false otherwise
1150     bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
1151     {
1152       Standard_Integer anArgumentIndex = 0;
1153       Quantity_Color   aColor1;
1154       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
1155       {
1156         return false;
1157       }
1158       Quantity_Color aColor2;
1159       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
1160       {
1161         return false;
1162       }
1163       const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1164         myGradientOptionKey);
1165       if (anArgumentIndex != aNumberOfGradientOptionArguments)
1166       {
1167         return false;
1168       }
1169       theColor1 = aColor1;
1170       theColor2 = aColor2;
1171       return true;
1172     }
1173
1174     //! Processes the gradient mode option
1175     //! @param theGradientMode the fill method used for a background gradient filling
1176     //! @return true if processing was successful, or false otherwise
1177     bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
1178     {
1179       return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
1180     }
1181
1182     //! Processes the gradient mode option
1183     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
1184     //! @param theGradientMode the fill method used for a background gradient filling
1185     //! @return true if processing was successful, or false otherwise
1186     bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
1187                                     Aspect_GradientFillMethod&        theGradientMode) const
1188     {
1189       return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
1190     }
1191
1192     //! Processes some mode option
1193     //! @tparam TheMode the type of a mode to be processed
1194     //! @param theModeOptionKey the key of the option that is interpreted as a mode option
1195     //! @param theMode a mode to be processed
1196     //! @return true if processing was successful, or false otherwise
1197     template <typename TheMode>
1198     bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
1199                             bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
1200                                                             TheMode& /* theMode */),
1201                             TheMode& theMode) const
1202     {
1203       const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1204         theModeOptionKey);
1205       if (aNumberOfModeOptionArguments != 1)
1206       {
1207         return false;
1208       }
1209       std::string aModeString;
1210       if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
1211       {
1212         return false;
1213       }
1214       TheMode aMode = TheMode();
1215       if (!theGetModeByName (aModeString.c_str(), aMode))
1216       {
1217         return false;
1218       }
1219       theMode = aMode;
1220       return true;
1221     }
1222
1223     //! Processes the color option
1224     //! @param theColor a color used for filling a background
1225     //! @return true if processing was successful, or false otherwise
1226     bool processColorOption (Quantity_Color& theColor) const
1227     {
1228       return processColorOption (myColorOptionKey, theColor);
1229     }
1230
1231     //! Processes the color option
1232     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1233     //! @param theColor a color used for filling a background
1234     //! @return true if processing was successful, or false otherwise
1235     bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
1236     {
1237       Standard_Integer anArgumentIndex = 0;
1238       Quantity_Color   aColor;
1239       if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
1240       {
1241         return false;
1242       }
1243       const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1244         theColorOptionKey);
1245       if (anArgumentIndex != aNumberOfColorOptionArguments)
1246       {
1247         return false;
1248       }
1249       theColor = aColor;
1250       return true;
1251     }
1252
1253     //! Prints helping message
1254     //! @param theBackgroundCommandName the name of the command that changes the background
1255     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1256     //! @return true if printing was successful, or false otherwise
1257     static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
1258     {
1259       return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
1260     }
1261
1262     //! Sets the cubemap as a background
1263     //! @param theFileNames the array of filenames of packed or multifile cubemap
1264     //! @param theOrder array of cubemap sides indexes mapping them from tiles in packed cubemap
1265     static void setCubeMap (const NCollection_Array1<TCollection_AsciiString>& theFileNames,
1266                             const Graphic3d_ValidatedCubeMapOrder              theOrder = Graphic3d_CubeMapOrder::Default(),
1267                             bool                                               theZIsInverted = false,
1268                             bool                                               theToGenPBREnv = true)
1269     {
1270       const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
1271       Handle(Graphic3d_CubeMap) aCubeMap;
1272
1273       if (theFileNames.Size() == 1)
1274         aCubeMap = new Graphic3d_CubeMapPacked(theFileNames[0], theOrder);
1275       else
1276         aCubeMap = new Graphic3d_CubeMapSeparate(theFileNames);
1277
1278       aCubeMap->SetZInversion (theZIsInverted);
1279
1280       aCubeMap->GetParams()->SetFilter(Graphic3d_TOTF_BILINEAR);
1281       aCubeMap->GetParams()->SetRepeat(Standard_False);
1282       aCubeMap->GetParams()->SetTextureUnit(Graphic3d_TextureUnit_EnvMap);
1283
1284       aCurrentView->SetBackgroundCubeMap (aCubeMap, theToGenPBREnv, Standard_True);
1285     }
1286
1287     //! Sets the image as a background
1288     //! @param theImageFileName the filename of the image to be used as a background
1289     //! @param theImageMode the fill type used for a background image
1290     static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
1291     {
1292       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1293       aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
1294     }
1295
1296     //! Sets the fill type used for a background image
1297     //! @param theImageMode the fill type used for a background image
1298     static void setImageMode (const Aspect_FillMethod theImageMode)
1299     {
1300       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1301       aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
1302     }
1303
1304     //! Sets the gradient filling for a background
1305     //! @param theColor1 the gradient starting color
1306     //! @param theColor2 the gradient ending color
1307     //! @param theGradientMode the fill method used for a background gradient filling
1308     static void setGradient (const Quantity_Color&           theColor1,
1309                              const Quantity_Color&           theColor2,
1310                              const Aspect_GradientFillMethod theGradientMode)
1311     {
1312       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1313       aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
1314     }
1315
1316     //! Sets the fill method used for a background gradient filling
1317     //! @param theGradientMode the fill method used for a background gradient filling
1318     static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
1319     {
1320       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1321       aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
1322     }
1323
1324     //! Sets the color used for filling a background
1325     //! @param theColor the color used for filling a background
1326     static void setColor (const Quantity_Color& theColor)
1327     {
1328       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1329       aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
1330       aCurrentView->SetBackgroundColor (theColor);
1331       aCurrentView->Update();
1332     }
1333
1334     //! Sets the gradient filling for a background in a default viewer
1335     //! @param theColor1 the gradient starting color
1336     //! @param theColor2 the gradient ending color
1337     //! @param theGradientMode the fill method used for a background gradient filling
1338     static void setDefaultGradient (const Quantity_Color&           theColor1,
1339                                     const Quantity_Color&           theColor2,
1340                                     const Aspect_GradientFillMethod theGradientMode)
1341     {
1342       ViewerTest_DefaultBackground.GradientColor1 = theColor1;
1343       ViewerTest_DefaultBackground.GradientColor2 = theColor2;
1344       ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
1345       setDefaultGradient();
1346     }
1347
1348     //! Sets the color used for filling a background in a default viewer
1349     //! @param theColor the color used for filling a background
1350     static void setDefaultColor (const Quantity_Color& theColor)
1351     {
1352       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
1353       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
1354       ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
1355       ViewerTest_DefaultBackground.FlatColor      = theColor;
1356       setDefaultGradient();
1357       setDefaultColor();
1358     }
1359
1360     //! Sets the gradient filling for a background in a default viewer.
1361     //! Gradient settings are taken from ViewerTest_DefaultBackground structure
1362     static void setDefaultGradient()
1363     {
1364       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1365              anInteractiveContextIterator (ViewerTest_myContexts);
1366            anInteractiveContextIterator.More();
1367            anInteractiveContextIterator.Next())
1368       {
1369         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1370         aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1371                                              ViewerTest_DefaultBackground.GradientColor2,
1372                                              ViewerTest_DefaultBackground.FillMethod);
1373       }
1374     }
1375
1376     //! Sets the color used for filling a background in a default viewer.
1377     //! The color value is taken from ViewerTest_DefaultBackground structure
1378     static void setDefaultColor()
1379     {
1380       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1381              anInteractiveContextIterator (ViewerTest_myContexts);
1382            anInteractiveContextIterator.More();
1383            anInteractiveContextIterator.Next())
1384       {
1385         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1386         aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1387       }
1388     }
1389   };
1390
1391 } // namespace
1392
1393 //==============================================================================
1394
1395 #ifdef _WIN32
1396 static LRESULT WINAPI AdvViewerWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
1397 #endif
1398
1399 //==============================================================================
1400 //function : WClass
1401 //purpose  :
1402 //==============================================================================
1403
1404 const Handle(WNT_WClass)& ViewerTest::WClass()
1405 {
1406   static Handle(WNT_WClass) theWClass;
1407 #if defined(_WIN32)
1408   if (theWClass.IsNull())
1409   {
1410     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
1411                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
1412                                 ::LoadCursor (NULL, IDC_ARROW));
1413   }
1414 #endif
1415   return theWClass;
1416 }
1417
1418 //==============================================================================
1419 //function : CreateName
1420 //purpose  : Create numerical name for new object in theMap
1421 //==============================================================================
1422 template <typename ObjectType>
1423 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
1424                                     const TCollection_AsciiString& theDefaultString)
1425 {
1426   if (theObjectMap.IsEmpty())
1427     return theDefaultString + TCollection_AsciiString(1);
1428
1429   Standard_Integer aNextKey = 1;
1430   Standard_Boolean isFound = Standard_False;
1431   while (!isFound)
1432   {
1433     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
1434     // Look for objects with default names
1435     if (theObjectMap.IsBound1(aStringKey))
1436     {
1437       aNextKey++;
1438     }
1439     else
1440       isFound = Standard_True;
1441   }
1442
1443   return theDefaultString + TCollection_AsciiString(aNextKey);
1444 }
1445
1446 //==============================================================================
1447 //structure : ViewerTest_Names
1448 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
1449 //==============================================================================
1450 struct ViewerTest_Names
1451 {
1452 private:
1453   TCollection_AsciiString myDriverName;
1454   TCollection_AsciiString myViewerName;
1455   TCollection_AsciiString myViewName;
1456
1457 public:
1458
1459   const TCollection_AsciiString& GetDriverName () const
1460   {
1461     return myDriverName;
1462   }
1463   void SetDriverName (const TCollection_AsciiString& theDriverName)
1464   {
1465     myDriverName = theDriverName;
1466   }
1467   const TCollection_AsciiString& GetViewerName () const
1468   {
1469     return myViewerName;
1470   }
1471   void SetViewerName (const TCollection_AsciiString& theViewerName)
1472   {
1473     myViewerName = theViewerName;
1474   }
1475   const TCollection_AsciiString& GetViewName () const
1476   {
1477     return myViewName;
1478   }
1479   void SetViewName (const TCollection_AsciiString& theViewName)
1480   {
1481     myViewName = theViewName;
1482   }
1483
1484   //===========================================================================
1485   //function : Constructor for ViewerTest_Names
1486   //purpose  : Get view, viewer, driver names from custom string
1487   //===========================================================================
1488
1489   ViewerTest_Names (const TCollection_AsciiString& theInputString)
1490   {
1491     TCollection_AsciiString aName(theInputString);
1492     if (theInputString.IsEmpty())
1493     {
1494       // Get current configuration
1495       if (ViewerTest_myDrivers.IsEmpty())
1496         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1497           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1498       else
1499         myDriverName = ViewerTest_myDrivers.Find2
1500         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1501
1502       if(ViewerTest_myContexts.IsEmpty())
1503       {
1504         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1505           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1506       }
1507       else
1508       {
1509         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
1510       }
1511
1512       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
1513     }
1514     else
1515     {
1516       // There is at least view name
1517       Standard_Integer aParserNumber = 0;
1518       for (Standard_Integer i = 0; i < 3; ++i)
1519       {
1520         Standard_Integer aParserPos = aName.SearchFromEnd("/");
1521         if(aParserPos != -1)
1522         {
1523           aParserNumber++;
1524           aName.Split(aParserPos-1);
1525         }
1526         else
1527           break;
1528       }
1529       if (aParserNumber == 0)
1530       {
1531         // Only view name
1532         if (!ViewerTest::GetAISContext().IsNull())
1533         {
1534           myDriverName = ViewerTest_myDrivers.Find2
1535           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1536           myViewerName = ViewerTest_myContexts.Find2
1537           (ViewerTest::GetAISContext());
1538         }
1539         else
1540         {
1541           // There is no opened contexts here, need to create names for viewer and driver
1542           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1543             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1544
1545           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1546             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1547         }
1548         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
1549       }
1550       else if (aParserNumber == 1)
1551       {
1552         // Here is viewerName/viewName
1553         if (!ViewerTest::GetAISContext().IsNull())
1554           myDriverName = ViewerTest_myDrivers.Find2
1555           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1556         else
1557         {
1558           // There is no opened contexts here, need to create name for driver
1559           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1560             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1561         }
1562         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
1563
1564         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
1565       }
1566       else
1567       {
1568         //Here is driverName/viewerName/viewName
1569         myDriverName = TCollection_AsciiString(aName);
1570
1571         TCollection_AsciiString aViewerName(theInputString);
1572         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
1573         myViewerName = TCollection_AsciiString(aViewerName);
1574
1575         myViewName = TCollection_AsciiString(theInputString);
1576       }
1577     }
1578   }
1579 };
1580
1581 //==============================================================================
1582 //function : FindContextByView
1583 //purpose  : Find AIS_InteractiveContext by View
1584 //==============================================================================
1585
1586 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
1587 {
1588   Handle(AIS_InteractiveContext) anAISContext;
1589
1590   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1591        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
1592   {
1593     if (anIter.Value()->CurrentViewer() == theView->Viewer())
1594        return anIter.Key2();
1595   }
1596   return anAISContext;
1597 }
1598
1599 //==============================================================================
1600 //function : IsWindowOverlapped
1601 //purpose  : Check if theWindow overlapp another view
1602 //==============================================================================
1603
1604 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
1605                                      const Standard_Integer thePxTop,
1606                                      const Standard_Integer thePxRight,
1607                                      const Standard_Integer thePxBottom,
1608                                      TCollection_AsciiString& theViewId)
1609 {
1610   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
1611       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1612   {
1613     Standard_Integer aTop = 0,
1614       aLeft = 0,
1615       aRight = 0,
1616       aBottom = 0;
1617     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
1618     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1619         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
1620         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1621         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
1622     {
1623       theViewId = anIter.Key1();
1624       return Standard_True;
1625     }
1626   }
1627   return Standard_False;
1628 }
1629
1630 // Workaround: to create and delete non-orthographic views outside ViewerTest
1631 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
1632 {
1633   ViewerTest_myViews.UnBind1 (theName);
1634 }
1635
1636 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
1637                                const Handle(V3d_View)& theView)
1638 {
1639   ViewerTest_myViews.Bind (theName, theView);
1640 }
1641
1642 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
1643 {
1644   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
1645 }
1646
1647 //==============================================================================
1648 //function : ViewerInit
1649 //purpose  : Create the window viewer and initialize all the global variable
1650 //==============================================================================
1651
1652 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
1653                                                 const Standard_Integer thePxTop,
1654                                                 const Standard_Integer thePxWidth,
1655                                                 const Standard_Integer thePxHeight,
1656                                                 const TCollection_AsciiString& theViewName,
1657                                                 const TCollection_AsciiString& theDisplayName,
1658                                                 const Handle(V3d_View)& theViewToClone,
1659                                                 const Standard_Boolean theIsVirtual)
1660 {
1661   // Default position and dimension of the viewer window.
1662   // Note that left top corner is set to be sufficiently small to have
1663   // window fit in the small screens (actual for remote desktops, see #23003).
1664   // The position corresponds to the window's client area, thus some
1665   // gap is added for window frame to be visible.
1666   Standard_Integer aPxLeft   = 20;
1667   Standard_Integer aPxTop    = 40;
1668   Standard_Integer aPxWidth  = 409;
1669   Standard_Integer aPxHeight = 409;
1670   Standard_Boolean toCreateViewer = Standard_False;
1671   const Standard_Boolean isVirtual = Draw_VirtualWindows || theIsVirtual;
1672   if (!theViewToClone.IsNull())
1673   {
1674     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1675   }
1676
1677   Handle(Graphic3d_GraphicDriverFactory) aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
1678   if (aFactory.IsNull())
1679   {
1680     Draw::GetInterpretor().Eval ("pload OPENGL");
1681     aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
1682     if (aFactory.IsNull())
1683     {
1684       Draw::GetInterpretor().Eval ("pload GLES");
1685       aFactory = Graphic3d_GraphicDriverFactory::DefaultDriverFactory();
1686       if (aFactory.IsNull())
1687       {
1688         throw Standard_ProgramError("Error: no graphic driver factory found");
1689       }
1690     }
1691   }
1692
1693   Handle(Graphic3d_GraphicDriver) aGraphicDriver;
1694   ViewerTest_Names aViewNames(theViewName);
1695   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
1696     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1697
1698   if (thePxLeft != 0)
1699     aPxLeft = thePxLeft;
1700   if (thePxTop != 0)
1701     aPxTop = thePxTop;
1702   if (thePxWidth != 0)
1703     aPxWidth = thePxWidth;
1704   if (thePxHeight != 0)
1705     aPxHeight = thePxHeight;
1706
1707   // Get graphic driver (create it or get from another view)
1708   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1709   if (isNewDriver)
1710   {
1711     // Get connection string
1712   #if defined(HAVE_XLIB)
1713     if (!theDisplayName.IsEmpty())
1714     {
1715       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1716     }
1717     else
1718     {
1719       Aspect_XDisplay* aDispX = NULL;
1720       // create dedicated display connection instead of reusing Tk connection
1721       // so that to proceed events independently through VProcessEvents()/ViewerMainLoop() callbacks
1722       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1723       Tcl_Interp* aTclInterp = aCommands.Interp();
1724       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1725       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1726       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1727     }
1728   #else
1729     (void)theDisplayName; // avoid warning on unused argument
1730     SetDisplayConnection (new Aspect_DisplayConnection ());
1731   #endif
1732
1733     aGraphicDriver = aFactory->CreateDriver (GetDisplayConnection());
1734     if (isVirtual)
1735     {
1736       // don't waste the time waiting for VSync when window is not displayed on the screen
1737       aGraphicDriver->SetVerticalSync (false);
1738     }
1739
1740     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1741     toCreateViewer = Standard_True;
1742   }
1743   else
1744   {
1745     aGraphicDriver = ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName());
1746   }
1747
1748   //Dispose the window if input parameters are default
1749   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1750   {
1751     Standard_Integer aTop = 0,
1752                      aLeft = 0,
1753                      aRight = 0,
1754                      aBottom = 0,
1755                      aScreenWidth = 0,
1756                      aScreenHeight = 0;
1757
1758     // Get screen resolution
1759 #if defined(_WIN32)
1760     RECT aWindowSize;
1761     GetClientRect(GetDesktopWindow(), &aWindowSize);
1762     aScreenHeight = aWindowSize.bottom;
1763     aScreenWidth = aWindowSize.right;
1764 #elif defined(HAVE_XLIB)
1765     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
1766     Screen* aScreen = DefaultScreenOfDisplay(aDispX);
1767     aScreenWidth  = WidthOfScreen(aScreen);
1768     aScreenHeight = HeightOfScreen(aScreen);
1769 #elif defined(__APPLE__)
1770     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1771 #else
1772     // not implemented
1773 #endif
1774
1775     TCollection_AsciiString anOverlappedViewId("");
1776
1777     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1778     {
1779       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1780
1781       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1782         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1783       {
1784         if (aBottom + aPxHeight + 40 > aScreenHeight)
1785         {
1786           aPxLeft = 20;
1787           aPxTop = 40;
1788           break;
1789         }
1790         aPxLeft = 20;
1791         aPxTop = aBottom + 40;
1792       }
1793       else
1794         aPxLeft = aRight + 20;
1795     }
1796   }
1797
1798   // Get viewer name
1799   TCollection_AsciiString aTitle("3D View - ");
1800   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1801
1802   // Change name of current active window
1803   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1804   {
1805     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1806   }
1807
1808   // Create viewer
1809   Handle(V3d_Viewer) a3DViewer;
1810   // If it's the single view, we first look for empty context
1811   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1812   {
1813     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1814       anIter(ViewerTest_myContexts);
1815     if (anIter.More())
1816       ViewerTest::SetAISContext (anIter.Value());
1817     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1818   }
1819   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1820   {
1821     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1822     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1823   }
1824   else if (a3DViewer.IsNull())
1825   {
1826     toCreateViewer = Standard_True;
1827     a3DViewer = new V3d_Viewer(aGraphicDriver);
1828     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1829     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1830                                            ViewerTest_DefaultBackground.GradientColor2,
1831                                            ViewerTest_DefaultBackground.FillMethod);
1832   }
1833
1834   // AIS context setup
1835   if (ViewerTest::GetAISContext().IsNull() ||
1836       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1837   {
1838     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1839     ViewerTest::SetAISContext (aContext);
1840     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1841   }
1842   else
1843   {
1844     ViewerTest::ResetEventManager();
1845   }
1846
1847   // Create window
1848 #if defined(_WIN32)
1849   VT_GetWindow() = new WNT_Window (aTitle.ToCString(), WClass(),
1850                                    isVirtual ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1851                                     aPxLeft, aPxTop,
1852                                     aPxWidth, aPxHeight,
1853                                     Quantity_NOC_BLACK);
1854   VT_GetWindow()->RegisterRawInputDevices (WNT_Window::RawInputMask_SpaceMouse);
1855 #elif defined(HAVE_XLIB)
1856   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1857                                   aTitle.ToCString(),
1858                                   aPxLeft, aPxTop,
1859                                   aPxWidth, aPxHeight);
1860 #elif defined(__APPLE__)
1861   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1862                                      aPxLeft, aPxTop,
1863                                      aPxWidth, aPxHeight);
1864   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1865 #else
1866   // not implemented
1867   VT_GetWindow() = new Aspect_NeutralWindow();
1868   VT_GetWindow()->SetSize (aPxWidth, aPxHeight);
1869 #endif
1870   VT_GetWindow()->SetVirtual (isVirtual);
1871
1872   // View setup
1873   Handle(V3d_View) aView;
1874   if (!theViewToClone.IsNull())
1875   {
1876     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1877   }
1878   else
1879   {
1880     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1881   }
1882
1883   aView->SetWindow (VT_GetWindow());
1884   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1885
1886   ViewerTest::CurrentView(aView);
1887   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1888
1889   // Setup for X11 or NT
1890   OSWindowSetup();
1891
1892   // Set parameters for V3d_View and V3d_Viewer
1893   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1894   aV3dView->SetComputedMode(Standard_False);
1895
1896   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1897   if (toCreateViewer)
1898   {
1899     a3DViewer->SetDefaultLights();
1900     a3DViewer->SetLightOn();
1901   }
1902
1903 #if defined(HAVE_XLIB)
1904   if (isNewDriver)
1905   {
1906     ::Display* aDispX = (::Display* )GetDisplayConnection()->GetDisplayAspect();
1907     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1908   }
1909 #endif
1910
1911   VT_GetWindow()->Map();
1912
1913   // Set the handle of created view in the event manager
1914   ViewerTest::ResetEventManager();
1915
1916   ViewerTest::CurrentView()->Redraw();
1917
1918   aView.Nullify();
1919   a3DViewer.Nullify();
1920
1921   return aViewNames.GetViewName();
1922 }
1923
1924 //==============================================================================
1925 //function : RedrawAllViews
1926 //purpose  : Redraw all created views
1927 //==============================================================================
1928 void ViewerTest::RedrawAllViews()
1929 {
1930   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1931   for (; aViewIt.More(); aViewIt.Next())
1932   {
1933     const Handle(V3d_View)& aView = aViewIt.Key2();
1934     aView->Redraw();
1935   }
1936 }
1937
1938 //==============================================================================
1939 //function : VDriver
1940 //purpose  :
1941 //==============================================================================
1942 static int VDriver (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1943 {
1944   if (theArgsNb == 1)
1945   {
1946     theDi << "Registered: ";
1947     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
1948          aFactoryIter.More(); aFactoryIter.Next())
1949     {
1950       const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
1951       theDi << aFactory->Name() << " ";
1952     }
1953
1954     theDi << "\n";
1955     theDi << "Default: ";
1956     if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
1957     {
1958       theDi << aFactory->Name();
1959     }
1960     else
1961     {
1962       theDi << "NONE";
1963     }
1964     return 0;
1965   }
1966
1967   TCollection_AsciiString aNewActive;
1968   bool toLoad = false;
1969   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
1970   {
1971     TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
1972     anArgCase.LowerCase();
1973     if (anArgCase == "-list")
1974     {
1975       for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
1976            aFactoryIter.More(); aFactoryIter.Next())
1977       {
1978         const Handle(Graphic3d_GraphicDriverFactory)& aFactory = aFactoryIter.Value();
1979         theDi << aFactory->Name() << " ";
1980       }
1981     }
1982     else if ((anArgCase == "-default"
1983            || anArgCase == "-load")
1984           && aNewActive.IsEmpty())
1985     {
1986       toLoad = (anArgCase == "-load");
1987       if (anArgIter + 1 < theArgsNb)
1988       {
1989         aNewActive = theArgVec[++anArgIter];
1990       }
1991       else if (toLoad)
1992       {
1993         theDi << "Syntax error at '" << theArgVec[anArgIter] << "'";
1994         return 1;
1995       }
1996       else
1997       {
1998         if (Handle(Graphic3d_GraphicDriverFactory) aFactory =  Graphic3d_GraphicDriverFactory::DefaultDriverFactory())
1999         {
2000           theDi << aFactory->Name();
2001         }
2002         else
2003         {
2004           theDi << "NONE";
2005         }
2006       }
2007     }
2008     else if (aNewActive.IsEmpty())
2009     {
2010       aNewActive = theArgVec[anArgIter];
2011     }
2012     else
2013     {
2014       theDi << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
2015       return 1;
2016     }
2017   }
2018
2019   if (!aNewActive.IsEmpty())
2020   {
2021     const TCollection_AsciiString aNameCopy = aNewActive;
2022     if (TCollection_AsciiString::IsSameString (aNewActive, "gl", false)
2023      || TCollection_AsciiString::IsSameString (aNewActive, "opengl", false)
2024      || TCollection_AsciiString::IsSameString (aNewActive, "tkopengl", false))
2025     {
2026       aNewActive = "tkopengl";
2027     }
2028     else if (TCollection_AsciiString::IsSameString (aNewActive, "gles", false)
2029           || TCollection_AsciiString::IsSameString (aNewActive, "opengles", false)
2030           || TCollection_AsciiString::IsSameString (aNewActive, "tkopengles", false))
2031     {
2032       aNewActive = "tkopengles";
2033     }
2034     else if (TCollection_AsciiString::IsSameString (aNewActive, "d3d", false)
2035           || TCollection_AsciiString::IsSameString (aNewActive, "d3dhost", false)
2036           || TCollection_AsciiString::IsSameString (aNewActive, "tkd3dhost", false))
2037     {
2038       aNewActive = "tkd3dhost";
2039     }
2040
2041     if (toLoad)
2042     {
2043       if (aNewActive == "tkopengl")
2044       {
2045         Draw::GetInterpretor().Eval ("pload OPENGL");
2046       }
2047       else if (aNewActive == "tkopengles")
2048       {
2049         Draw::GetInterpretor().Eval ("pload GLES");
2050       }
2051       else if (aNewActive == "tkd3dhost")
2052       {
2053         Draw::GetInterpretor().Eval ("pload D3DHOST");
2054       }
2055       else
2056       {
2057         theDi << "Syntax error: unable to load plugin for unknown driver factory '" << aNameCopy << "'";
2058         return 1;
2059       }
2060     }
2061
2062     bool isFound = false;
2063     for (Graphic3d_GraphicDriverFactoryList::Iterator aFactoryIter (Graphic3d_GraphicDriverFactory::DriverFactories());
2064          aFactoryIter.More(); aFactoryIter.Next())
2065     {
2066       Handle(Graphic3d_GraphicDriverFactory) aFactory = aFactoryIter.Value();
2067       if (TCollection_AsciiString::IsSameString (aFactory->Name(), aNewActive, false))
2068       {
2069         Graphic3d_GraphicDriverFactory::RegisterFactory (aFactory, true);
2070         isFound = true;
2071         break;
2072       }
2073     }
2074
2075     if (!isFound)
2076     {
2077       theDi << "Syntax error: driver factory '" << aNameCopy << "' not found";
2078       return 1;
2079     }
2080   }
2081
2082   return 0;
2083 }
2084
2085 //==============================================================================
2086 //function : Vinit
2087 //purpose  : Create the window viewer and initialize all the global variable
2088 //    Use Tcl_CreateFileHandler on UNIX to catch the X11 Viewer event
2089 //==============================================================================
2090 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2091 {
2092   TCollection_AsciiString aViewName, aDisplayName;
2093   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
2094   Standard_Boolean isVirtual = false;
2095   Handle(V3d_View) aCopyFrom;
2096   TCollection_AsciiString aName, aValue;
2097   int is2dMode = -1;
2098   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
2099   {
2100     const TCollection_AsciiString anArg = theArgVec[anArgIt];
2101     TCollection_AsciiString anArgCase = anArg;
2102     anArgCase.LowerCase();
2103     if (anArgIt + 1 < theArgsNb
2104      && anArgCase == "-name")
2105     {
2106       aViewName = theArgVec[++anArgIt];
2107     }
2108     else if (anArgIt + 1 < theArgsNb
2109           && (anArgCase == "-left"
2110            || anArgCase == "-l"))
2111     {
2112       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
2113     }
2114     else if (anArgIt + 1 < theArgsNb
2115           && (anArgCase == "-top"
2116            || anArgCase == "-t"))
2117     {
2118       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
2119     }
2120     else if (anArgIt + 1 < theArgsNb
2121           && (anArgCase == "-width"
2122            || anArgCase == "-w"))
2123     {
2124       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
2125     }
2126     else if (anArgIt + 1 < theArgsNb
2127           && (anArgCase == "-height"
2128            || anArgCase == "-h"))
2129     {
2130       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
2131     }
2132     else if (anArgCase == "-virtual"
2133           || anArgCase == "-offscreen")
2134     {
2135       isVirtual = true;
2136       if (anArgIt + 1 < theArgsNb
2137        && Draw::ParseOnOff (theArgVec[anArgIt + 1], isVirtual))
2138       {
2139         ++anArgIt;
2140       }
2141     }
2142     else if (anArgCase == "-exitonclose")
2143     {
2144       ViewerTest_EventManager::ToExitOnCloseView() = true;
2145       if (anArgIt + 1 < theArgsNb
2146        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
2147       {
2148         ++anArgIt;
2149       }
2150     }
2151     else if (anArgCase == "-closeonescape"
2152           || anArgCase == "-closeonesc")
2153     {
2154       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
2155       if (anArgIt + 1 < theArgsNb
2156        && Draw::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
2157       {
2158         ++anArgIt;
2159       }
2160     }
2161     else if (anArgCase == "-2d_mode"
2162           || anArgCase == "-2dmode"
2163           || anArgCase == "-2d")
2164     {
2165       bool toEnable = true;
2166       if (anArgIt + 1 < theArgsNb
2167        && Draw::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
2168       {
2169         ++anArgIt;
2170       }
2171       is2dMode = toEnable ? 1 : 0;
2172     }
2173     else if (anArgIt + 1 < theArgsNb
2174           && (anArgCase == "-disp"
2175            || anArgCase == "-display"))
2176     {
2177       aDisplayName = theArgVec[++anArgIt];
2178     }
2179     else if (!ViewerTest::CurrentView().IsNull()
2180           &&  aCopyFrom.IsNull()
2181           && (anArgCase == "-copy"
2182            || anArgCase == "-clone"
2183            || anArgCase == "-cloneactive"
2184            || anArgCase == "-cloneactiveview"))
2185     {
2186       aCopyFrom = ViewerTest::CurrentView();
2187     }
2188     // old syntax
2189     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
2190     {
2191       aName.LowerCase();
2192       if (aName == "name")
2193       {
2194         aViewName = aValue;
2195       }
2196       else if (aName == "l"
2197             || aName == "left")
2198       {
2199         aPxLeft = aValue.IntegerValue();
2200       }
2201       else if (aName == "t"
2202             || aName == "top")
2203       {
2204         aPxTop = aValue.IntegerValue();
2205       }
2206       else if (aName == "disp"
2207             || aName == "display")
2208       {
2209         aDisplayName = aValue;
2210       }
2211       else if (aName == "w"
2212             || aName == "width")
2213       {
2214         aPxWidth = aValue.IntegerValue();
2215       }
2216       else if (aName == "h"
2217             || aName == "height")
2218       {
2219         aPxHeight = aValue.IntegerValue();
2220       }
2221       else
2222       {
2223         Message::SendFail() << "Syntax error: unknown argument " << anArg;
2224         return 1;
2225       }
2226     }
2227     else if (aViewName.IsEmpty())
2228     {
2229       aViewName = anArg;
2230     }
2231     else
2232     {
2233       Message::SendFail() << "Syntax error: unknown argument " << anArg;
2234       return 1;
2235     }
2236   }
2237
2238 #if !defined(HAVE_XLIB)
2239   if (!aDisplayName.IsEmpty())
2240   {
2241     aDisplayName.Clear();
2242     Message::SendWarning() << "Warning: display parameter will be ignored.\n";
2243   }
2244 #endif
2245
2246   ViewerTest_Names aViewNames (aViewName);
2247   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2248   {
2249     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2250     theDi.Eval (aCommand.ToCString());
2251     if (is2dMode != -1)
2252     {
2253       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2254     }
2255     return 0;
2256   }
2257
2258   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2259                                                             aViewName, aDisplayName, aCopyFrom, isVirtual);
2260   if (is2dMode != -1)
2261   {
2262     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2263   }
2264   theDi << aViewId;
2265   return 0;
2266 }
2267
2268 //! Parse HLR algo type.
2269 static Standard_Boolean parseHlrAlgoType (const char* theName,
2270                                           Prs3d_TypeOfHLR& theType)
2271 {
2272   TCollection_AsciiString aName (theName);
2273   aName.LowerCase();
2274   if (aName == "polyalgo")
2275   {
2276     theType = Prs3d_TOH_PolyAlgo;
2277   }
2278   else if (aName == "algo")
2279   {
2280     theType = Prs3d_TOH_Algo;
2281   }
2282   else
2283   {
2284     return Standard_False;
2285   }
2286   return Standard_True;
2287 }
2288
2289 //==============================================================================
2290 //function : VHLR
2291 //purpose  : hidden lines removal algorithm
2292 //==============================================================================
2293
2294 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2295 {
2296   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2297   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2298   if (aView.IsNull())
2299   {
2300     Message::SendFail ("Error: no active viewer");
2301     return 1;
2302   }
2303
2304   Standard_Boolean hasHlrOnArg = Standard_False;
2305   Standard_Boolean hasShowHiddenArg = Standard_False;
2306   Standard_Boolean isHLROn = Standard_False;
2307   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2308   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2309   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2310   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2311   {
2312     TCollection_AsciiString anArg (argv[anArgIter]);
2313     anArg.LowerCase();
2314     if (anUpdateTool.parseRedrawMode (anArg))
2315     {
2316       continue;
2317     }
2318     else if (anArg == "-showhidden"
2319           && anArgIter + 1 < argc
2320           && Draw::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2321     {
2322       ++anArgIter;
2323       hasShowHiddenArg = Standard_True;
2324       continue;
2325     }
2326     else if ((anArg == "-type"
2327            || anArg == "-algo"
2328            || anArg == "-algotype")
2329           && anArgIter + 1 < argc
2330           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2331     {
2332       ++anArgIter;
2333       continue;
2334     }
2335     else if (!hasHlrOnArg
2336           && Draw::ParseOnOff (argv[anArgIter], isHLROn))
2337     {
2338       hasHlrOnArg = Standard_True;
2339       continue;
2340     }
2341     // old syntax
2342     else if (!hasShowHiddenArg
2343           && Draw::ParseOnOff(argv[anArgIter], toShowHidden))
2344     {
2345       hasShowHiddenArg = Standard_True;
2346       continue;
2347     }
2348     else
2349     {
2350       Message::SendFail() << "Syntax error at '" << argv[anArgIter] << "'";
2351       return 1;
2352     }
2353   }
2354   if (!hasHlrOnArg)
2355   {
2356     di << "HLR:        " << aView->ComputedMode() << "\n";
2357     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2358     di << "HlrAlgo:    ";
2359     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2360     {
2361       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2362       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2363       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2364     }
2365     anUpdateTool.Invalidate();
2366     return 0;
2367   }
2368
2369   Standard_Boolean toRecompute = Standard_False;
2370   if (aTypeOfHLR != Prs3d_TOH_NotSet
2371    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2372   {
2373     toRecompute = Standard_True;
2374     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2375   }
2376   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2377   {
2378     toRecompute = Standard_True;
2379     if (toShowHidden)
2380     {
2381       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2382     }
2383     else
2384     {
2385       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2386     }
2387   }
2388
2389   // redisplay shapes
2390   if (aView->ComputedMode() && isHLROn && toRecompute)
2391   {
2392     AIS_ListOfInteractive aListOfShapes;
2393     aCtx->DisplayedObjects (aListOfShapes);
2394     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2395     {
2396       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2397       {
2398         aCtx->Redisplay (aShape, Standard_False);
2399       }
2400     }
2401   }
2402
2403   aView->SetComputedMode (isHLROn);
2404   return 0;
2405 }
2406
2407 //==============================================================================
2408 //function : VHLRType
2409 //purpose  : change type of using HLR algorithm
2410 //==============================================================================
2411
2412 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2413 {
2414   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2415   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2416   if (aView.IsNull())
2417   {
2418     Message::SendFail ("Error: no active viewer");
2419     return 1;
2420   }
2421
2422   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2423   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2424   AIS_ListOfInteractive aListOfShapes;
2425   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2426   {
2427     TCollection_AsciiString anArg (argv[anArgIter]);
2428     anArg.LowerCase();
2429     if (anUpdateTool.parseRedrawMode (anArg))
2430     {
2431       continue;
2432     }
2433     else if ((anArg == "-type"
2434            || anArg == "-algo"
2435            || anArg == "-algotype")
2436           && anArgIter + 1 < argc
2437           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2438     {
2439       ++anArgIter;
2440       continue;
2441     }
2442     // old syntax
2443     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2444           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2445     {
2446       continue;
2447     }
2448     else
2449     {
2450       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2451       TCollection_AsciiString aName (argv[anArgIter]);
2452       if (!aMap.IsBound2 (aName))
2453       {
2454         Message::SendFail() << "Syntax error: Wrong shape name '" << aName << "'";
2455         return 1;
2456       }
2457
2458       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2459       if (aShape.IsNull())
2460       {
2461         Message::SendFail() << "Syntax error: '" << aName << "' is not a shape presentation";
2462         return 1;
2463       }
2464       aListOfShapes.Append (aShape);
2465       continue;
2466     }
2467   }
2468   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2469   {
2470     Message::SendFail ("Syntax error: wrong number of arguments");
2471     return 1;
2472   }
2473
2474   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2475   if (isGlobal)
2476   {
2477     aCtx->DisplayedObjects (aListOfShapes);
2478     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2479   }
2480
2481   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2482   {
2483     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2484     if (aShape.IsNull())
2485     {
2486       continue;
2487     }
2488
2489     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2490                             && aView->ComputedMode();
2491     if (!isGlobal
2492      || aShape->TypeOfHLR() != aTypeOfHLR)
2493     {
2494       aShape->SetTypeOfHLR (aTypeOfHLR);
2495     }
2496     if (toUpdateShape)
2497     {
2498       aCtx->Redisplay (aShape, Standard_False);
2499     }
2500   }
2501   return 0;
2502 }
2503
2504 //==============================================================================
2505 //function : FindViewIdByWindowHandle
2506 //purpose  : Find theView Id in the map of views by window handle
2507 //==============================================================================
2508 #if defined(_WIN32) || defined(HAVE_XLIB)
2509 static TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2510 {
2511   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2512        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2513   {
2514     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2515     if (aWindowHandle == theWindowHandle)
2516       return anIter.Key1();
2517   }
2518   return TCollection_AsciiString("");
2519 }
2520 #endif
2521
2522 //! Make the view active
2523 void ActivateView (const TCollection_AsciiString& theViewName,
2524                    Standard_Boolean theToUpdate = Standard_True)
2525 {
2526   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2527   if (aView.IsNull())
2528   {
2529     return;
2530   }
2531
2532   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2533   if (!anAISContext.IsNull())
2534   {
2535     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2536     {
2537       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2538     }
2539
2540     ViewerTest::CurrentView (aView);
2541     ViewerTest::SetAISContext (anAISContext);
2542     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2543 #if defined(_WIN32)
2544     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
2545 #elif defined(HAVE_XLIB)
2546     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
2547 #elif defined(__APPLE__)
2548     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
2549 #else
2550     VT_GetWindow() = Handle(Aspect_NeutralWindow)::DownCast(ViewerTest::CurrentView()->Window());
2551 #endif
2552     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2553     if (theToUpdate)
2554     {
2555       ViewerTest::CurrentView()->Redraw();
2556     }
2557   }
2558 }
2559
2560 //==============================================================================
2561 //function : RemoveView
2562 //purpose  :
2563 //==============================================================================
2564 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2565                              const Standard_Boolean  theToRemoveContext)
2566 {
2567   if (!ViewerTest_myViews.IsBound2 (theView))
2568   {
2569     return;
2570   }
2571
2572   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2573   RemoveView (aViewName, theToRemoveContext);
2574 }
2575
2576 //==============================================================================
2577 //function : RemoveView
2578 //purpose  : Close and remove view from display, clear maps if necessary
2579 //==============================================================================
2580 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2581 {
2582   if (!ViewerTest_myViews.IsBound1(theViewName))
2583   {
2584     Message::SendFail() << "Wrong view name";
2585     return;
2586   }
2587
2588   // Activate another view if it's active now
2589   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2590   {
2591     if (ViewerTest_myViews.Extent() > 1)
2592     {
2593       TCollection_AsciiString aNewViewName;
2594       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2595            anIter.More(); anIter.Next())
2596       {
2597         if (anIter.Key1() != theViewName)
2598         {
2599           aNewViewName = anIter.Key1();
2600           break;
2601         }
2602       }
2603       ActivateView (aNewViewName);
2604     }
2605     else
2606     {
2607       VT_GetWindow().Nullify();
2608       ViewerTest::CurrentView (Handle(V3d_View)());
2609       if (isContextRemoved)
2610       {
2611         Handle(AIS_InteractiveContext) anEmptyContext;
2612         ViewerTest::SetAISContext(anEmptyContext);
2613       }
2614     }
2615   }
2616
2617   // Delete view
2618   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2619   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2620   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2621   aRedrawer.Stop (aView->Window());
2622
2623   // Remove view resources
2624   ViewerTest_myViews.UnBind1(theViewName);
2625   aView->Window()->Unmap();
2626   aView->Remove();
2627
2628 #if defined(HAVE_XLIB)
2629   XFlush ((::Display* )GetDisplayConnection()->GetDisplayAspect());
2630 #endif
2631
2632   // Keep context opened only if the closed view is last to avoid
2633   // unused empty contexts
2634   if (!aCurrentContext.IsNull())
2635   {
2636     // Check if there are more difined views in the viewer
2637     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1)
2638      && aCurrentContext->CurrentViewer()->DefinedViews().IsEmpty())
2639     {
2640       // Remove driver if there is no viewers that use it
2641       Standard_Boolean isRemoveDriver = Standard_True;
2642       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2643           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2644       {
2645         if (aCurrentContext != anIter.Key2() &&
2646           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2647         {
2648           isRemoveDriver = Standard_False;
2649           break;
2650         }
2651       }
2652
2653       aCurrentContext->RemoveAll (Standard_False);
2654       if(isRemoveDriver)
2655       {
2656         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2657       #if defined(HAVE_XLIB)
2658         Tcl_DeleteFileHandler (XConnectionNumber ((::Display* )aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplayAspect()));
2659       #endif
2660       }
2661
2662       ViewerTest_myContexts.UnBind2(aCurrentContext);
2663     }
2664   }
2665   Message::SendInfo() << "3D View - " << theViewName << " was deleted.\n";
2666   if (ViewerTest_EventManager::ToExitOnCloseView())
2667   {
2668     Draw_Interprete ("exit");
2669   }
2670 }
2671
2672 //==============================================================================
2673 //function : VClose
2674 //purpose  : Remove the view defined by its name
2675 //==============================================================================
2676
2677 static int VClose (Draw_Interpretor& /*theDi*/,
2678                    Standard_Integer  theArgsNb,
2679                    const char**      theArgVec)
2680 {
2681   NCollection_List<TCollection_AsciiString> aViewList;
2682   if (theArgsNb > 1)
2683   {
2684     TCollection_AsciiString anArg (theArgVec[1]);
2685     anArg.UpperCase();
2686     if (anArg.IsEqual ("ALL")
2687      || anArg.IsEqual ("*"))
2688     {
2689       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2690            anIter.More(); anIter.Next())
2691       {
2692         aViewList.Append (anIter.Key1());
2693       }
2694       if (aViewList.IsEmpty())
2695       {
2696         std::cout << "No view to close\n";
2697         return 0;
2698       }
2699     }
2700     else
2701     {
2702       ViewerTest_Names aViewName (theArgVec[1]);
2703       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2704       {
2705         Message::SendFail() << "Error: the view with name '" << theArgVec[1] << "' does not exist";
2706         return 1;
2707       }
2708       aViewList.Append (aViewName.GetViewName());
2709     }
2710   }
2711   else
2712   {
2713     // close active view
2714     if (ViewerTest::CurrentView().IsNull())
2715     {
2716       Message::SendFail ("Error: no active view");
2717       return 1;
2718     }
2719     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2720   }
2721
2722   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2723   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2724        anIter.More(); anIter.Next())
2725   {
2726     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2727   }
2728
2729   return 0;
2730 }
2731
2732 //==============================================================================
2733 //function : VActivate
2734 //purpose  : Activate the view defined by its ID
2735 //==============================================================================
2736
2737 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2738 {
2739   if (theArgsNb == 1)
2740   {
2741     theDi.Eval("vviewlist");
2742     return 0;
2743   }
2744
2745   TCollection_AsciiString aNameString;
2746   Standard_Boolean toUpdate = Standard_True;
2747   Standard_Boolean toActivate = Standard_True;
2748   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2749   {
2750     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2751     anArg.LowerCase();
2752     if (toUpdate
2753      && anArg == "-noupdate")
2754     {
2755       toUpdate = Standard_False;
2756     }
2757     else if (toActivate
2758           && aNameString.IsEmpty()
2759           && anArg == "none")
2760     {
2761       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2762       VT_GetWindow().Nullify();
2763       ViewerTest::CurrentView (Handle(V3d_View)());
2764       ViewerTest::ResetEventManager();
2765       theDi << theArgVec[0] << ": all views are inactive\n";
2766       toActivate = Standard_False;
2767     }
2768     else if (toActivate
2769           && aNameString.IsEmpty())
2770     {
2771       aNameString = theArgVec[anArgIter];
2772     }
2773     else
2774     {
2775       Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
2776       return 1;
2777     }
2778   }
2779
2780   if (!toActivate)
2781   {
2782     return 0;
2783   }
2784   else if (aNameString.IsEmpty())
2785   {
2786     Message::SendFail ("Syntax error: wrong number of arguments");
2787     return 1;
2788   }
2789
2790   // Check if this view exists in the viewer with the driver
2791   ViewerTest_Names aViewNames (aNameString);
2792   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2793   {
2794     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2795     return 1;
2796   }
2797
2798   // Check if it is active already
2799   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2800   {
2801     theDi << theArgVec[0] << ": the view is active already\n";
2802     return 0;
2803   }
2804
2805   ActivateView (aViewNames.GetViewName(), toUpdate);
2806   return 0;
2807 }
2808
2809 //==============================================================================
2810 //function : VViewList
2811 //purpose  : Print current list of views per viewer and graphic driver ID
2812 //           shared between viewers
2813 //==============================================================================
2814
2815 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2816 {
2817   if (theArgsNb > 2)
2818   {
2819     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2820           << "Usage: " << theArgVec[0] << " name";
2821     return 1;
2822   }
2823   if (ViewerTest_myContexts.Size() < 1)
2824     return 0;
2825
2826   Standard_Boolean isTreeView =
2827     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2828
2829   if (isTreeView)
2830   {
2831     theDi << theArgVec[0] <<":\n";
2832   }
2833
2834   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2835        aDriverIter.More(); aDriverIter.Next())
2836   {
2837     if (isTreeView)
2838       theDi << aDriverIter.Key1() << ":\n";
2839
2840     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2841       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2842     {
2843       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2844       {
2845         if (isTreeView)
2846         {
2847           TCollection_AsciiString aContextName(aContextIter.Key1());
2848           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2849         }
2850
2851         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2852              aViewIter.More(); aViewIter.Next())
2853         {
2854           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2855           {
2856             TCollection_AsciiString aViewName(aViewIter.Key1());
2857             if (isTreeView)
2858             {
2859               if (aViewIter.Value() == ViewerTest::CurrentView())
2860                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2861               else
2862                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2863             }
2864             else
2865             {
2866               theDi << aViewName << " ";
2867             }
2868           }
2869         }
2870       }
2871     }
2872   }
2873   return 0;
2874 }
2875
2876 //==============================================================================
2877 //function : GetMousePosition
2878 //purpose  :
2879 //==============================================================================
2880 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2881                                    Standard_Integer& theY)
2882 {
2883   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2884   {
2885     theX = aViewCtrl->LastMousePosition().x();
2886     theY = aViewCtrl->LastMousePosition().y();
2887   }
2888 }
2889
2890 //==============================================================================
2891 //function : VViewProj
2892 //purpose  : Switch view projection
2893 //==============================================================================
2894 static int VViewProj (Draw_Interpretor& ,
2895                       Standard_Integer theNbArgs,
2896                       const char** theArgVec)
2897 {
2898   static Standard_Boolean isYup = Standard_False;
2899   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2900   if (aView.IsNull())
2901   {
2902     Message::SendFail ("Error: no active viewer");
2903     return 1;
2904   }
2905
2906   TCollection_AsciiString aCmdName (theArgVec[0]);
2907   Standard_Boolean isGeneralCmd = Standard_False;
2908   if (aCmdName == "vfront")
2909   {
2910     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2911   }
2912   else if (aCmdName == "vback")
2913   {
2914     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2915   }
2916   else if (aCmdName == "vtop")
2917   {
2918     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2919   }
2920   else if (aCmdName == "vbottom")
2921   {
2922     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2923   }
2924   else if (aCmdName == "vleft")
2925   {
2926     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2927   }
2928   else if (aCmdName == "vright")
2929   {
2930     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2931   }
2932   else if (aCmdName == "vaxo")
2933   {
2934     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2935   }
2936   else
2937   {
2938     isGeneralCmd = Standard_True;
2939     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2940     {
2941       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2942       anArgCase.LowerCase();
2943       if (anArgCase == "-zup")
2944       {
2945         isYup = Standard_False;
2946       }
2947       else if (anArgCase == "-yup")
2948       {
2949         isYup = Standard_True;
2950       }
2951       else if (anArgCase == "-front"
2952             || anArgCase == "front"
2953             || anArgCase == "-f"
2954             || anArgCase == "f")
2955       {
2956         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2957       }
2958       else if (anArgCase == "-back"
2959             || anArgCase == "back"
2960             || anArgCase == "-b"
2961             || anArgCase == "b")
2962       {
2963         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2964       }
2965       else if (anArgCase == "-top"
2966             || anArgCase == "top"
2967             || anArgCase == "-t"
2968             || anArgCase == "t")
2969       {
2970         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2971       }
2972       else if (anArgCase == "-bottom"
2973             || anArgCase == "bottom"
2974             || anArgCase == "-bot"
2975             || anArgCase == "bot"
2976             || anArgCase == "-b"
2977             || anArgCase == "b")
2978       {
2979         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2980       }
2981       else if (anArgCase == "-left"
2982             || anArgCase == "left"
2983             || anArgCase == "-l"
2984             || anArgCase == "l")
2985       {
2986         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2987       }
2988       else if (anArgCase == "-right"
2989             || anArgCase == "right"
2990             || anArgCase == "-r"
2991             || anArgCase == "r")
2992       {
2993         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2994       }
2995       else if (anArgCase == "-axoleft"
2996             || anArgCase == "-leftaxo"
2997             || anArgCase == "axoleft"
2998             || anArgCase == "leftaxo")
2999       {
3000         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
3001       }
3002       else if (anArgCase == "-axo"
3003             || anArgCase == "axo"
3004             || anArgCase == "-a"
3005             || anArgCase == "a"
3006             || anArgCase == "-axoright"
3007             || anArgCase == "-rightaxo"
3008             || anArgCase == "axoright"
3009             || anArgCase == "rightaxo")
3010       {
3011         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
3012       }
3013       else if (anArgCase == "+x")
3014       {
3015         aView->SetProj (V3d_Xpos, isYup);
3016       }
3017       else if (anArgCase == "-x")
3018       {
3019         aView->SetProj (V3d_Xneg, isYup);
3020       }
3021       else if (anArgCase == "+y")
3022       {
3023         aView->SetProj (V3d_Ypos, isYup);
3024       }
3025       else if (anArgCase == "-y")
3026       {
3027         aView->SetProj (V3d_Yneg, isYup);
3028       }
3029       else if (anArgCase == "+z")
3030       {
3031         aView->SetProj (V3d_Zpos, isYup);
3032       }
3033       else if (anArgCase == "-z")
3034       {
3035         aView->SetProj (V3d_Zneg, isYup);
3036       }
3037       else if (anArgCase == "+x+y+z")
3038       {
3039         aView->SetProj (V3d_XposYposZpos, isYup);
3040       }
3041       else if (anArgCase == "+x+y-z")
3042       {
3043         aView->SetProj (V3d_XposYposZneg, isYup);
3044       }
3045       else if (anArgCase == "+x-y+z")
3046       {
3047         aView->SetProj (V3d_XposYnegZpos, isYup);
3048       }
3049       else if (anArgCase == "+x-y-z")
3050       {
3051         aView->SetProj (V3d_XposYnegZneg, isYup);
3052       }
3053       else if (anArgCase == "-x+y+z")
3054       {
3055         aView->SetProj (V3d_XnegYposZpos, isYup);
3056       }
3057       else if (anArgCase == "-x+y-z")
3058       {
3059         aView->SetProj (V3d_XnegYposZneg, isYup);
3060       }
3061       else if (anArgCase == "-x-y+z")
3062       {
3063         aView->SetProj (V3d_XnegYnegZpos, isYup);
3064       }
3065       else if (anArgCase == "-x-y-z")
3066       {
3067         aView->SetProj (V3d_XnegYnegZneg, isYup);
3068       }
3069       else if (anArgCase == "+x+y")
3070       {
3071         aView->SetProj (V3d_XposYpos, isYup);
3072       }
3073       else if (anArgCase == "+x-y")
3074       {
3075         aView->SetProj (V3d_XposYneg, isYup);
3076       }
3077       else if (anArgCase == "-x+y")
3078       {
3079         aView->SetProj (V3d_XnegYpos, isYup);
3080       }
3081       else if (anArgCase == "-x-y")
3082       {
3083         aView->SetProj (V3d_XnegYneg, isYup);
3084       }
3085       else if (anArgCase == "+x+z")
3086       {
3087         aView->SetProj (V3d_XposZpos, isYup);
3088       }
3089       else if (anArgCase == "+x-z")
3090       {
3091         aView->SetProj (V3d_XposZneg, isYup);
3092       }
3093       else if (anArgCase == "-x+z")
3094       {
3095         aView->SetProj (V3d_XnegZpos, isYup);
3096       }
3097       else if (anArgCase == "-x-z")
3098       {
3099         aView->SetProj (V3d_XnegZneg, isYup);
3100       }
3101       else if (anArgCase == "+y+z")
3102       {
3103         aView->SetProj (V3d_YposZpos, isYup);
3104       }
3105       else if (anArgCase == "+y-z")
3106       {
3107         aView->SetProj (V3d_YposZneg, isYup);
3108       }
3109       else if (anArgCase == "-y+z")
3110       {
3111         aView->SetProj (V3d_YnegZpos, isYup);
3112       }
3113       else if (anArgCase == "-y-z")
3114       {
3115         aView->SetProj (V3d_YnegZneg, isYup);
3116       }
3117       else if (anArgIter + 1 < theNbArgs
3118             && anArgCase == "-frame"
3119             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
3120       {
3121         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
3122         aFrameDef.LowerCase();
3123         gp_Dir aRight, anUp;
3124         if (aFrameDef.Value (2) == aFrameDef.Value (4))
3125         {
3126           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3127           return 1;
3128         }
3129
3130         if (aFrameDef.Value (2) == 'x')
3131         {
3132           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
3133         }
3134         else if (aFrameDef.Value (2) == 'y')
3135         {
3136           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
3137         }
3138         else if (aFrameDef.Value (2) == 'z')
3139         {
3140           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
3141         }
3142         else
3143         {
3144           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3145           return 1;
3146         }
3147
3148         if (aFrameDef.Value (4) == 'x')
3149         {
3150           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
3151         }
3152         else if (aFrameDef.Value (4) == 'y')
3153         {
3154           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
3155         }
3156         else if (aFrameDef.Value (4) == 'z')
3157         {
3158           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
3159         }
3160         else
3161         {
3162           Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3163           return 1;
3164         }
3165
3166         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
3167         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
3168         const gp_Dir aDir = anUp.Crossed (aRight);
3169         aCamera->SetCenter (gp_Pnt (0, 0, 0));
3170         aCamera->SetDirection (aDir);
3171         aCamera->SetUp (anUp);
3172         aCamera->OrthogonalizeUp();
3173
3174         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
3175         aView->Update();
3176       }
3177       else
3178       {
3179         Message::SendFail() << "Syntax error at '" << theArgVec[anArgIter] << "'";
3180         return 1;
3181       }
3182     }
3183   }
3184
3185   if (!isGeneralCmd
3186     && theNbArgs != 1)
3187   {
3188     Message::SendFail ("Syntax error: wrong number of arguments");
3189     return 1;
3190   }
3191   return 0;
3192 }
3193
3194 //==============================================================================
3195 //function : VHelp
3196 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
3197 //Draw arg : No args
3198 //==============================================================================
3199
3200 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
3201 {
3202   di << "=========================\n";
3203   di << "F : FitAll\n";
3204   di << "T : TopView\n";
3205   di << "B : BottomView\n";
3206   di << "R : RightView\n";
3207   di << "L : LeftView\n";
3208   di << "Backspace : AxonometricView\n";
3209
3210   di << "=========================\n";
3211   di << "W, S : Fly   forward/backward\n";
3212   di << "A, D : Slide left/right\n";
3213   di << "Q, E : Bank  left/right\n";
3214   di << "-, + : Change flying speed\n";
3215   di << "Arrows : look left/right/up/down\n";
3216   di << "Arrows+Shift : slide left/right/up/down\n";
3217
3218   di << "=========================\n";
3219   di << "S + Ctrl : Shading\n";
3220   di << "W + Ctrl : Wireframe\n";
3221   di << "H : HiddenLineRemoval\n";
3222   di << "U : Unset display mode\n";
3223   di << "Delete : Remove selection from viewer\n";
3224
3225   di << "=========================\n";
3226   di << "Selection mode \n";
3227   di << "0 : Shape\n";
3228   di << "1 : Vertex\n";
3229   di << "2 : Edge\n";
3230   di << "3 : Wire\n";
3231   di << "4 : Face\n";
3232   di << "5 : Shell\n";
3233   di << "6 : Solid\n";
3234   di << "7 : Compound\n";
3235
3236   di << "=========================\n";
3237   di << "< : Hilight next detected\n";
3238   di << "> : Hilight previous detected\n";
3239
3240   return 0;
3241 }
3242
3243 #ifdef _WIN32
3244
3245 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
3246                                            UINT theMsg,
3247                                            WPARAM wParam,
3248                                            LPARAM lParam )
3249 {
3250   if (ViewerTest_myViews.IsEmpty())
3251   {
3252     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3253   }
3254
3255   switch (theMsg)
3256   {
3257     case WM_CLOSE:
3258     {
3259       // Delete view from map of views
3260       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3261       return 0;
3262     }
3263     case WM_ACTIVATE:
3264     {
3265       if (LOWORD(wParam) == WA_CLICKACTIVE
3266        || LOWORD(wParam) == WA_ACTIVE
3267        || ViewerTest::CurrentView().IsNull())
3268       {
3269         // Activate inactive window
3270         if (VT_GetWindow().IsNull()
3271          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3272         {
3273           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3274         }
3275       }
3276       return 0;
3277     }
3278     case WM_LBUTTONDOWN:
3279     {
3280       TheIsAnimating = Standard_False;
3281     }
3282     Standard_FALLTHROUGH
3283     default:
3284     {
3285       const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3286       if (!aView.IsNull()
3287        && !VT_GetWindow().IsNull())
3288       {
3289         MSG aMsg = {};
3290         aMsg.hwnd = theWinHandle;
3291         aMsg.message = theMsg;
3292         aMsg.wParam = wParam;
3293         aMsg.lParam = lParam;
3294         if (VT_GetWindow()->ProcessMessage (*ViewerTest::CurrentEventManager(), aMsg))
3295         {
3296           return 0;
3297         }
3298       }
3299     }
3300   }
3301   return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3302 }
3303
3304 //==============================================================================
3305 //function : ViewerMainLoop
3306 //purpose  : Get a Event on the view and dispatch it
3307 //==============================================================================
3308
3309 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3310 {
3311   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3312   if (aViewCtrl.IsNull()
3313    || theNbArgs < 4)
3314   {
3315     return 0;
3316   }
3317
3318   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3319
3320   std::cout << "Start picking\n";
3321
3322   MSG aMsg;
3323   aMsg.wParam = 1;
3324   while (aViewCtrl->ToPickPoint())
3325   {
3326     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3327     if (GetMessageW (&aMsg, NULL, 0, 0))
3328     {
3329       TranslateMessage (&aMsg);
3330       DispatchMessageW (&aMsg);
3331     }
3332   }
3333
3334   std::cout << "Picking done\n";
3335   return 0;
3336 }
3337
3338 #elif defined(HAVE_XLIB)
3339
3340 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3341 {
3342   static XEvent aReport;
3343   const Standard_Boolean toPick = theNbArgs > 0;
3344   if (theNbArgs > 0)
3345   {
3346     if (ViewerTest::CurrentEventManager().IsNull())
3347     {
3348       return 0;
3349     }
3350     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3351   }
3352
3353   Display* aDisplay = (Display* )GetDisplayConnection()->GetDisplayAspect();
3354   XNextEvent (aDisplay, &aReport);
3355
3356   // Handle event for the chosen display connection
3357   switch (aReport.type)
3358   {
3359     case ClientMessage:
3360     {
3361       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3362       {
3363         // Close the window
3364         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3365         return toPick ? 0 : 1;
3366       }
3367       break;
3368     }
3369     case FocusIn:
3370     {
3371       // Activate inactive view
3372       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3373       if (aWindow != aReport.xfocus.window)
3374       {
3375         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3376       }