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