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