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