Increment OCCT version up to 7.4.0
[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_ListOfInteractive.hxx>
26 #include <AIS_ListIteratorOfListOfInteractive.hxx>
27 #include <AIS_Manipulator.hxx>
28 #include <AIS_ViewCube.hxx>
29 #include <AIS_Shape.hxx>
30 #include <Aspect_DisplayConnection.hxx>
31 #include <Aspect_Grid.hxx>
32 #include <Aspect_TypeOfLine.hxx>
33 #include <Draw.hxx>
34 #include <Draw_Appli.hxx>
35 #include <Draw_Interpretor.hxx>
36 #include <Draw_ProgressIndicator.hxx>
37 #include <gp_Dir.hxx>
38 #include <gp_Pln.hxx>
39 #include <gp_Pnt.hxx>
40 #include <Graphic3d_ArrayOfPolylines.hxx>
41 #include <Graphic3d_AspectFillArea3d.hxx>
42 #include <Graphic3d_AspectMarker3d.hxx>
43 #include <Graphic3d_ClipPlane.hxx>
44 #include <Graphic3d_CubeMapPacked.hxx>
45 #include <Graphic3d_CubeMapSeparate.hxx>
46 #include <Graphic3d_GraduatedTrihedron.hxx>
47 #include <Graphic3d_NameOfTextureEnv.hxx>
48 #include <Graphic3d_Texture2Dmanual.hxx>
49 #include <Graphic3d_TextureEnv.hxx>
50 #include <Graphic3d_TextureParams.hxx>
51 #include <Graphic3d_TypeOfTextureFilter.hxx>
52 #include <Image_AlienPixMap.hxx>
53 #include <Image_Diff.hxx>
54 #include <Image_VideoRecorder.hxx>
55 #include <Message_ProgressSentry.hxx>
56 #include <NCollection_DataMap.hxx>
57 #include <NCollection_List.hxx>
58 #include <NCollection_Vector.hxx>
59 #include <OSD.hxx>
60 #include <OSD_Timer.hxx>
61 #include <OpenGl_GraphicDriver.hxx>
62 #include <Prs3d_ShadingAspect.hxx>
63 #include <Prs3d_Drawer.hxx>
64 #include <Prs3d_LineAspect.hxx>
65 #include <Prs3d_Root.hxx>
66 #include <Prs3d_Text.hxx>
67 #include <Select3D_SensitivePrimitiveArray.hxx>
68 #include <TColStd_HSequenceOfAsciiString.hxx>
69 #include <TColStd_SequenceOfInteger.hxx>
70 #include <TColStd_HSequenceOfReal.hxx>
71 #include <TColgp_Array1OfPnt2d.hxx>
72 #include <TColStd_MapOfAsciiString.hxx>
73 #include <ViewerTest_AutoUpdater.hxx>
74 #include <ViewerTest_EventManager.hxx>
75 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
76 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
77 #include <ViewerTest_CmdParser.hxx>
78 #include <ViewerTest_V3dView.hxx>
79 #include <V3d_AmbientLight.hxx>
80 #include <V3d_DirectionalLight.hxx>
81 #include <V3d_PositionalLight.hxx>
82 #include <V3d_SpotLight.hxx>
83
84 #include <tcl.h>
85
86 #include <cstdlib>
87
88 #if defined(_WIN32)
89   #include <WNT_WClass.hxx>
90   #include <WNT_Window.hxx>
91 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
92   #include <Cocoa_Window.hxx>
93 #else
94   #include <Xw_Window.hxx>
95   #include <X11/Xlib.h> /* contains some dangerous #defines such as Status, True etc. */
96   #include <X11/Xutil.h>
97   #include <tk.h>
98 #endif
99
100 //==============================================================================
101 //  VIEWER GLOBAL VARIABLES
102 //==============================================================================
103
104 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
105 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
106
107 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
108 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
109
110 #if defined(_WIN32)
111 static Handle(WNT_Window)& VT_GetWindow() {
112   static Handle(WNT_Window) WNTWin;
113   return WNTWin;
114 }
115 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
116 static Handle(Cocoa_Window)& VT_GetWindow()
117 {
118   static Handle(Cocoa_Window) aWindow;
119   return aWindow;
120 }
121 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
122 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
123
124 #else
125 static Handle(Xw_Window)& VT_GetWindow(){
126   static Handle(Xw_Window) XWWin;
127   return XWWin;
128 }
129
130 static void VProcessEvents(ClientData,int);
131 #endif
132
133 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
134 {
135   static Handle(Aspect_DisplayConnection) aDisplayConnection;
136   return aDisplayConnection;
137 }
138
139 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
140 {
141   GetDisplayConnection() = theDisplayConnection;
142 }
143
144 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
145 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
146 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
147 static OpenGl_Caps ViewerTest_myDefaultCaps;
148
149 static void OSWindowSetup();
150
151 static struct
152 {
153   Quantity_Color FlatColor;
154   Quantity_Color GradientColor1;
155   Quantity_Color GradientColor2;
156   Aspect_GradientFillMethod FillMethod;
157 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
158
159 //==============================================================================
160 //  EVENT GLOBAL VARIABLES
161 //==============================================================================
162
163 Standard_Boolean TheIsAnimating = Standard_False;
164
165 namespace
166 {
167
168   //! Checks if some set is a subset of other set
169   //! @tparam TheSuperSet the type of the superset
170   //! @tparam TheSubSet the type of the subset
171   //! @param theSuperSet the superset
172   //! @param theSubSet the subset to be checked
173   //! @return true if the superset includes subset, or false otherwise
174   template <typename TheSuperSet, typename TheSubSet>
175   static bool includes (const TheSuperSet& theSuperSet, const TheSubSet& theSubSet)
176   {
177     return std::includes (theSuperSet.begin(), theSuperSet.end(), theSubSet.begin(), theSubSet.end());
178   }
179
180   //! A variable set of keys for command-line options.
181   //! It includes a set of mandatory keys and a set of all possible keys.
182   class CommandOptionKeyVariableSet
183   {
184   public:
185     //! Default constructor
186     CommandOptionKeyVariableSet()
187     {
188     }
189
190     //! Constructor
191     //! @param theMandatoryKeySet the set of the mandatory option keys
192     //! @param theAdditionalKeySet the set of additional options that could be omitted
193     CommandOptionKeyVariableSet (
194       const ViewerTest_CommandOptionKeySet& theMandatoryKeySet,
195       const ViewerTest_CommandOptionKeySet& theAdditionalKeySet = ViewerTest_CommandOptionKeySet())
196     : myMandatoryKeySet (theMandatoryKeySet)
197     {
198       std::set_union (theMandatoryKeySet.begin(),
199                       theMandatoryKeySet.end(),
200                       theAdditionalKeySet.begin(),
201                       theAdditionalKeySet.end(),
202                       std::inserter (myFullKeySet, myFullKeySet.begin()));
203     }
204
205     //! Checks if the set of option keys fits to the current variable set (it must contain all mandatory keys
206     //! and be contained in the full key set)
207     //! @param theCheckedKeySet the set of option keys to be checked
208     bool IsInSet (const ViewerTest_CommandOptionKeySet& theCheckedKeySet) const
209     {
210       return includes (theCheckedKeySet, myMandatoryKeySet) && includes (myFullKeySet, theCheckedKeySet);
211     }
212
213   private:
214     //! A set of mandatory command-line option keys
215     ViewerTest_CommandOptionKeySet myMandatoryKeySet;
216
217     //! A full set of command-line option keys (includes mandatory and additional option keys)
218     ViewerTest_CommandOptionKeySet myFullKeySet;
219   };
220
221   //! Gets some code by its name
222   //! @tparam TheCode the type of a code to be found
223   //! @param theCodeNameMap the map from code names to codes
224   //! @param theCodeName the name of a code to be found
225   //! @param theCode the code to be found
226   //! @return true if a code is found, or false otherwise
227   template <typename TheCode>
228   static bool getSomeCodeByName (const std::map<TCollection_AsciiString, TheCode>& theCodeNameMap,
229                                  TCollection_AsciiString                           theCodeName,
230                                  TheCode&                                          theCode)
231   {
232     theCodeName.LowerCase();
233     const typename std::map<TCollection_AsciiString, TheCode>::const_iterator aCodeIterator = theCodeNameMap.find (
234       theCodeName);
235     if (aCodeIterator == theCodeNameMap.end())
236     {
237       return false;
238     }
239     theCode = aCodeIterator->second;
240     return true;
241   }
242
243   // Defines possible commands related to background changing
244   enum BackgroundCommand
245   {
246     BackgroundCommand_Main,              //!< The main command that manages other commands through options
247     BackgroundCommand_Image,             //!< Sets an image as a background
248     BackgroundCommand_ImageMode,         //!< Changes a background image mode
249     BackgroundCommand_Gradient,          //!< Sets a gradient as a background
250     BackgroundCommand_GradientMode,      //!< Changes a background gradient mode
251     BackgroundCommand_Color,             //!< Fills background with a specified color
252     BackgroundCommand_Default            //!< Sets the background default color or gradient
253   };
254
255   //! Map from background command names to its codes
256   typedef std::map<TCollection_AsciiString, BackgroundCommand> BackgroundCommandNameMap;
257
258   //! Creates a map from background command names to its codes
259   //! @return a map from background command names to its codes
260   static BackgroundCommandNameMap createBackgroundCommandNameMap()
261   {
262     BackgroundCommandNameMap aBackgroundCommandNameMap;
263     aBackgroundCommandNameMap["vbackground"]      = BackgroundCommand_Main;
264     aBackgroundCommandNameMap["vsetbg"]           = BackgroundCommand_Image;
265     aBackgroundCommandNameMap["vsetbgmode"]       = BackgroundCommand_ImageMode;
266     aBackgroundCommandNameMap["vsetgradientbg"]   = BackgroundCommand_Gradient;
267     aBackgroundCommandNameMap["vsetgrbgmode"]     = BackgroundCommand_GradientMode;
268     aBackgroundCommandNameMap["vsetcolorbg"]      = BackgroundCommand_Color;
269     aBackgroundCommandNameMap["vsetdefaultbg"]    = BackgroundCommand_Default;
270     return aBackgroundCommandNameMap;
271   }
272
273   //! Gets a background command by its name
274   //! @param theBackgroundCommandName the name of the background command
275   //! @param theBackgroundCommand the background command to be found
276   //! @return true if a background command is found, or false otherwise
277   static bool getBackgroundCommandByName (const TCollection_AsciiString& theBackgroundCommandName,
278                                           BackgroundCommand&             theBackgroundCommand)
279   {
280     static const BackgroundCommandNameMap THE_BACKGROUND_COMMAND_NAME_MAP = createBackgroundCommandNameMap();
281     return getSomeCodeByName (THE_BACKGROUND_COMMAND_NAME_MAP, theBackgroundCommandName, theBackgroundCommand);
282   }
283
284   //! Map from background image fill method names to its codes
285   typedef std::map<TCollection_AsciiString, Aspect_FillMethod> BackgroundImageFillMethodNameMap;
286
287   //! Creates a map from background image fill method names to its codes
288   //! @return a map from background image fill method names to its codes
289   static BackgroundImageFillMethodNameMap createBackgroundImageFillMethodNameMap()
290   {
291     BackgroundImageFillMethodNameMap aBackgroundImageFillMethodNameMap;
292     aBackgroundImageFillMethodNameMap["none"]     = Aspect_FM_NONE;
293     aBackgroundImageFillMethodNameMap["centered"] = Aspect_FM_CENTERED;
294     aBackgroundImageFillMethodNameMap["tiled"]    = Aspect_FM_TILED;
295     aBackgroundImageFillMethodNameMap["stretch"]  = Aspect_FM_STRETCH;
296     return aBackgroundImageFillMethodNameMap;
297   }
298
299   //! Gets a background image fill method by its name
300   //! @param theBackgroundImageFillMethodName the name of the background image fill method
301   //! @param theBackgroundImageFillMethod the background image fill method to be found
302   //! @return true if a background image fill method is found, or false otherwise
303   static bool getBackgroundImageFillMethodByName (const TCollection_AsciiString& theBackgroundImageFillMethodName,
304                                                   Aspect_FillMethod&             theBackgroundImageFillMethod)
305   {
306     static const BackgroundImageFillMethodNameMap THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP =
307       createBackgroundImageFillMethodNameMap();
308     return getSomeCodeByName (THE_BACKGROUND_IMAGE_FILL_METHOD_NAME_MAP,
309                               theBackgroundImageFillMethodName,
310                               theBackgroundImageFillMethod);
311   }
312
313   //! Map from background gradient fill method names to its codes
314   typedef std::map<TCollection_AsciiString, Aspect_GradientFillMethod> BackgroundGradientFillMethodNameMap;
315
316   //! Creates a map from background gradient fill method names to its codes
317   //! @return a map from background gradient fill method names to its codes
318   static BackgroundGradientFillMethodNameMap createBackgroundGradientFillMethodNameMap()
319   {
320     BackgroundGradientFillMethodNameMap aBackgroundGradientFillMethodNameMap;
321     aBackgroundGradientFillMethodNameMap["none"]       = Aspect_GFM_NONE;
322     aBackgroundGradientFillMethodNameMap["hor"]        = Aspect_GFM_HOR;
323     aBackgroundGradientFillMethodNameMap["horizontal"] = Aspect_GFM_HOR;
324     aBackgroundGradientFillMethodNameMap["ver"]        = Aspect_GFM_VER;
325     aBackgroundGradientFillMethodNameMap["vertical"]   = Aspect_GFM_VER;
326     aBackgroundGradientFillMethodNameMap["diag1"]      = Aspect_GFM_DIAG1;
327     aBackgroundGradientFillMethodNameMap["diagonal1"]  = Aspect_GFM_DIAG1;
328     aBackgroundGradientFillMethodNameMap["diag2"]      = Aspect_GFM_DIAG2;
329     aBackgroundGradientFillMethodNameMap["diagonal2"]  = Aspect_GFM_DIAG2;
330     aBackgroundGradientFillMethodNameMap["corner1"]    = Aspect_GFM_CORNER1;
331     aBackgroundGradientFillMethodNameMap["corner2"]    = Aspect_GFM_CORNER2;
332     aBackgroundGradientFillMethodNameMap["corner3"]    = Aspect_GFM_CORNER3;
333     aBackgroundGradientFillMethodNameMap["corner4"]    = Aspect_GFM_CORNER4;
334     return aBackgroundGradientFillMethodNameMap;
335   }
336
337   //! Gets a gradient fill method by its name
338   //! @param theBackgroundGradientFillMethodName the name of the gradient fill method
339   //! @param theBackgroundGradientFillMethod the gradient fill method to be found
340   //! @return true if a gradient fill method is found, or false otherwise
341   static bool getBackgroundGradientFillMethodByName (const TCollection_AsciiString& theBackgroundGradientFillMethodName,
342                                                      Aspect_GradientFillMethod&     theBackgroundGradientFillMethod)
343   {
344     static const BackgroundGradientFillMethodNameMap THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP =
345       createBackgroundGradientFillMethodNameMap();
346     return getSomeCodeByName (THE_BACKGROUND_GRADIENT_FILL_METHOD_NAME_MAP,
347                               theBackgroundGradientFillMethodName,
348                               theBackgroundGradientFillMethod);
349   }
350
351   //! Changes the background in accordance with passed command line options
352   class BackgroundChanger
353   {
354   public:
355     //! Constructor. Prepares the command parser
356     BackgroundChanger()
357     {
358       prepareCommandParser();
359     }
360
361     //! Processes the command line and changes the background
362     //! @param theDrawInterpretor the interpreter of the Draw Harness application
363     //! @param theNumberOfCommandLineArguments the number of passed command line arguments
364     //! @param theCommandLineArguments the array of command line arguments
365     bool ProcessCommandLine (Draw_Interpretor&        theDrawInterpretor,
366                              const Standard_Integer   theNumberOfCommandLineArguments,
367                              const char* const* const theCommandLineArguments)
368     {
369       const char* const aBackgroundCommandName = theCommandLineArguments[0];
370       BackgroundCommand aBackgroundCommand = BackgroundCommand_Main;
371       if (!getBackgroundCommandByName (aBackgroundCommandName, aBackgroundCommand))
372       {
373         return false;
374       }
375       addCommandDescription (aBackgroundCommand);
376       myCommandParser.Parse (theNumberOfCommandLineArguments, theCommandLineArguments);
377       return processCommandOptions (aBackgroundCommandName, aBackgroundCommand, theDrawInterpretor);
378     }
379
380   private:
381     //! The type of functions that are able to set gradient background filling
382     typedef void SetGradientFunction (const Quantity_Color& /* theColor1 */,
383                                       const Quantity_Color& /* theColor2 */,
384                                       const Aspect_GradientFillMethod /* theGradientMode */);
385
386     //! The type of functions that are able to fill a background with a specific color
387     typedef void SetColorFunction (const Quantity_Color& /* theColor */);
388
389     //! the command parser used to parse command line options and its arguments
390     ViewerTest_CmdParser myCommandParser;
391
392     //! the option key for the command that sets an image as a background
393     ViewerTest_CommandOptionKey myImageOptionKey;
394
395     //! the option key for the command that sets a background image fill type
396     ViewerTest_CommandOptionKey myImageModeOptionKey;
397
398     //! the option key for the command that sets a gradient filling for the background
399     ViewerTest_CommandOptionKey myGradientOptionKey;
400
401     //! the option key for the command that sets a background gradient filling method
402     ViewerTest_CommandOptionKey myGradientModeOptionKey;
403
404     //! the option key for the command that fills background with a specific color
405     ViewerTest_CommandOptionKey myColorOptionKey;
406
407     //! the option key for the command that sets default background gradient or color
408     ViewerTest_CommandOptionKey myDefaultOptionKey;
409
410     //! the option key for the command that sets an environment cubemap as a background
411     ViewerTest_CommandOptionKey myCubeMapOptionKey;
412
413     //! the option key for the command that defines order of tiles in one image packed cubemap
414     ViewerTest_CommandOptionKey myCubeMapOrderOptionKey;
415
416     //! the option key for the command that sets inversion of Z axis for background cubemap
417     ViewerTest_CommandOptionKey myCubeMapInvertedZOptionKey;
418
419     //! the variable set of options that are allowed for the old scenario (without any option passed)
420     CommandOptionKeyVariableSet myUnnamedOptionVariableSet;
421
422     //! the variable set of options that are allowed for setting an environment cubemap as background
423     CommandOptionKeyVariableSet myCubeMapOptionVariableSet;
424
425     //! the variable set of options that are allowed for setting an image as a background
426     CommandOptionKeyVariableSet myImageOptionVariableSet;
427
428     //! the variable set of options that are allowed for setting a background image fill type
429     CommandOptionKeyVariableSet myImageModeOptionVariableSet;
430
431     //! the variable set of options that are allowed for setting a gradient filling for the background
432     CommandOptionKeyVariableSet myGradientOptionVariableSet;
433
434     //! the variable set of options that are allowed for setting a background gradient filling method
435     CommandOptionKeyVariableSet myGradientModeOptionVariableSet;
436
437     //! the variable set of options that are allowed for filling a background with a specific color
438     CommandOptionKeyVariableSet myColorOptionVariableSet;
439
440     //! the variable set of options that are allowed for setting a default background gradient
441     CommandOptionKeyVariableSet myDefaultGradientOptionVariableSet;
442
443     //! the variable set of options that are allowed for setting a default background color
444     CommandOptionKeyVariableSet myDefaultColorOptionVariableSet;
445
446     //! the variable set of options that are allowed for printing help
447     CommandOptionKeyVariableSet myHelpOptionVariableSet;
448
449     //! Adds options to command parser
450     void addOptionsToCommandParser()
451     {
452       myImageOptionKey     = myCommandParser.AddOption ("imageFile|image|imgFile|img",
453                                                     "filename of image used as background");
454       myImageModeOptionKey = myCommandParser.AddOption (
455         "imageMode|imgMode", "image fill type, should be one of CENTERED, TILED, STRETCH, NONE");
456       myGradientOptionKey = myCommandParser.AddOption ("gradient|grad|gr",
457                                                        "sets background gradient starting and ending colors");
458       myGradientModeOptionKey =
459         myCommandParser.AddOption ("gradientMode|gradMode|gradMd|grMode|grMd",
460                                    "gradient fill method, should be one of NONE, HOR[IZONTAL], VER[TICAL], "
461                                    "DIAG[ONAL]1, DIAG[ONAL]2, CORNER1, CORNER2, CORNER3, CORNER4");
462       myColorOptionKey   = myCommandParser.AddOption ("color|col", "background color");
463       myDefaultOptionKey = myCommandParser.AddOption ("default|def", "sets background default gradient or color");
464
465       myCubeMapOptionKey           = myCommandParser.AddOption ("cubemap|cmap|cm", "background cubemap");
466       myCubeMapOrderOptionKey      = myCommandParser.AddOption ("order|o", "order of sides in one image packed cubemap");
467       myCubeMapInvertedZOptionKey = myCommandParser.AddOption (
468         "invertedz|invz|iz", "whether Z axis is inverted or not during background cubemap rendering");
469     }
470
471     //! Creates option sets used to determine if a passed option set is valid or not
472     void createOptionSets()
473     {
474       ViewerTest_CommandOptionKeySet anUnnamedOptionSet;
475       anUnnamedOptionSet.insert (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
476       myUnnamedOptionVariableSet = CommandOptionKeyVariableSet (anUnnamedOptionSet);
477
478       ViewerTest_CommandOptionKeySet aCubeMapOptionSet;
479       aCubeMapOptionSet.insert (myCubeMapOptionKey);
480       ViewerTest_CommandOptionKeySet aCubeMapAdditionalOptionKeySet;
481       aCubeMapAdditionalOptionKeySet.insert (myCubeMapInvertedZOptionKey);
482       aCubeMapAdditionalOptionKeySet.insert (myCubeMapOrderOptionKey);
483       myCubeMapOptionVariableSet     = CommandOptionKeyVariableSet (aCubeMapOptionSet, aCubeMapAdditionalOptionKeySet);
484
485       ViewerTest_CommandOptionKeySet anImageOptionSet;
486       anImageOptionSet.insert (myImageOptionKey);
487       ViewerTest_CommandOptionKeySet anImageModeOptionSet;
488       anImageModeOptionSet.insert (myImageModeOptionKey);
489       myImageOptionVariableSet     = CommandOptionKeyVariableSet (anImageOptionSet, anImageModeOptionSet);
490       myImageModeOptionVariableSet = CommandOptionKeyVariableSet (anImageModeOptionSet);
491
492       ViewerTest_CommandOptionKeySet aGradientOptionSet;
493       aGradientOptionSet.insert (myGradientOptionKey);
494       ViewerTest_CommandOptionKeySet aGradientModeOptionSet;
495       aGradientModeOptionSet.insert (myGradientModeOptionKey);
496       myGradientOptionVariableSet     = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
497       myGradientModeOptionVariableSet = CommandOptionKeyVariableSet (aGradientModeOptionSet);
498
499       ViewerTest_CommandOptionKeySet aColorOptionSet;
500       aColorOptionSet.insert (myColorOptionKey);
501       myColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
502
503       aGradientOptionSet.insert (myDefaultOptionKey);
504       myDefaultGradientOptionVariableSet = CommandOptionKeyVariableSet (aGradientOptionSet, aGradientModeOptionSet);
505       aColorOptionSet.insert (myDefaultOptionKey);
506       myDefaultColorOptionVariableSet = CommandOptionKeyVariableSet (aColorOptionSet);
507
508       ViewerTest_CommandOptionKeySet aHelpOptionSet;
509       aHelpOptionSet.insert (ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
510       myHelpOptionVariableSet = CommandOptionKeyVariableSet (aHelpOptionSet);
511     }
512
513     //! Prepares the command parser. Adds options and creates option sets used to determine
514     //! if a passed option set is valid or not
515     void prepareCommandParser()
516     {
517       addOptionsToCommandParser();
518       createOptionSets();
519     }
520
521     //! Adds a command description to the command parser
522     //! @param theBackgroundCommand the key of the command which description is added to the command parser
523     void addCommandDescription (const BackgroundCommand theBackgroundCommand)
524     {
525       std::string aDescription;
526       bool        isMainCommand = false;
527       switch (theBackgroundCommand)
528       {
529         case BackgroundCommand_Main:
530           aDescription  = "Command: vbackground (changes background or some background settings)";
531           isMainCommand = true;
532           break;
533         case BackgroundCommand_Image:
534           aDescription = "Command: vsetbg (loads image as a background)";
535           break;
536         case BackgroundCommand_ImageMode:
537           aDescription = "Command: vsetbgmode (changes background fill type)";
538           break;
539         case BackgroundCommand_Gradient:
540           aDescription = "Command: vsetgradientbg (mounts gradient background)";
541           break;
542         case BackgroundCommand_GradientMode:
543           aDescription = "Command: vsetgradientbgmode (changes gradient background fill method)";
544           break;
545         case BackgroundCommand_Color:
546           aDescription = "Command: vsetcolorbg (sets color background)";
547           break;
548         case BackgroundCommand_Default:
549           aDescription = "Command: vsetdefaultbg (sets default viewer background gradient or fill color)";
550           break;
551         default:
552           return;
553       }
554       if (!isMainCommand)
555       {
556         aDescription += "\nThis command is obsolete. Use vbackground instead.";
557       }
558       myCommandParser.SetDescription (aDescription);
559     }
560
561     //! Check if a viewer is needed to be initialized
562     //! @param theBackgroundCommand the key of the command that changes the background
563     //! @return true if processing was successful, or false otherwise
564     bool checkViewerIsNeeded (const BackgroundCommand theBackgroundCommand) const
565     {
566       const bool                           isMain             = (theBackgroundCommand == BackgroundCommand_Main);
567       const ViewerTest_CommandOptionKeySet aUsedOptions       = myCommandParser.GetUsedOptions();
568       const bool                           aViewerIsNotNeeded =
569         (theBackgroundCommand == BackgroundCommand_Default)
570         || (myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
571         || (myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
572         || myHelpOptionVariableSet.IsInSet (aUsedOptions);
573       return !aViewerIsNotNeeded;
574     }
575
576     //! Check if a viewer is initialized
577     //! @param theBackgroundCommandName the name of the command that changes the background
578     //! @param theDrawInterpretor the interpreter of the Draw Harness application
579     //! @return true if a viewer is initialized, or false otherwise
580     static bool checkViewerIsInitialized (const char* const theBackgroundCommandName,
581                                           Draw_Interpretor& theDrawInterpretor)
582     {
583       const Handle (AIS_InteractiveContext)& anAISContext = ViewerTest::GetAISContext();
584       if (anAISContext.IsNull())
585       {
586         theDrawInterpretor << "Use 'vinit' command before executing '" << theBackgroundCommandName << "' command.\n";
587         return false;
588       }
589       return true;
590     }
591
592     //! Processes command options
593     //! @param theBackgroundCommandName the name of the command that changes the background
594     //! @param theBackgroundCommand the key of the command that changes the background
595     //! @param theDrawInterpretor the interpreter of the Draw Harness application
596     //! @return true if processing was successful, or false otherwise
597     bool processCommandOptions (const char* const       theBackgroundCommandName,
598                                 const BackgroundCommand theBackgroundCommand,
599                                 Draw_Interpretor&       theDrawInterpretor) const
600     {
601       if (myCommandParser.HasNoOption())
602       {
603         return printHelp (theBackgroundCommandName, theDrawInterpretor);
604       }
605       if (checkViewerIsNeeded (theBackgroundCommand)
606           && !checkViewerIsInitialized (theBackgroundCommandName, theDrawInterpretor))
607       {
608         return false;
609       }
610       if (myCommandParser.HasOnlyUnnamedOption())
611       {
612         return processUnnamedOption (theBackgroundCommand);
613       }
614       return processNamedOptions (theBackgroundCommandName, theBackgroundCommand, theDrawInterpretor);
615     }
616
617     //! Processes the unnamed option
618     //! @param theBackgroundCommand the key of the command that changes the background
619     //! @return true if processing was successful, or false otherwise
620     bool processUnnamedOption (const BackgroundCommand theBackgroundCommand) const
621     {
622       switch (theBackgroundCommand)
623       {
624         case BackgroundCommand_Main:
625           return false;
626         case BackgroundCommand_Image:
627           return processImageUnnamedOption();
628         case BackgroundCommand_ImageMode:
629           return processImageModeUnnamedOption();
630         case BackgroundCommand_Gradient:
631           return processGradientUnnamedOption();
632         case BackgroundCommand_GradientMode:
633           return processGradientModeUnnamedOption();
634         case BackgroundCommand_Color:
635           return processColorUnnamedOption();
636         case BackgroundCommand_Default:
637           return processDefaultUnnamedOption();
638         default:
639           return false;
640       }
641     }
642
643     //! Processes the image unnamed option
644     //! @return true if processing was successful, or false otherwise
645     bool processImageUnnamedOption() const
646     {
647       const std::size_t aNumberOfImageUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
648         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
649       if ((aNumberOfImageUnnamedOptionArguments != 1) && (aNumberOfImageUnnamedOptionArguments != 2))
650       {
651         return false;
652       }
653       std::string anImageFileName;
654       if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 0, anImageFileName))
655       {
656         return false;
657       }
658       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
659       if (aNumberOfImageUnnamedOptionArguments == 2)
660       {
661         std::string anImageModeString;
662         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, 1, anImageModeString))
663         {
664           return false;
665         }
666         if (!getBackgroundImageFillMethodByName (anImageModeString.c_str(), anImageMode))
667         {
668           return false;
669         }
670       }
671       setImage (anImageFileName.c_str(), anImageMode);
672       return true;
673     }
674
675     //! Processes the image mode unnamed option
676     //! @return true if processing was successful, or false otherwise
677     bool processImageModeUnnamedOption() const
678     {
679       return processImageModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
680     }
681
682     //! Processes the gradient unnamed option
683     //! @param theSetGradient the function used to set a background gradient filling
684     //! @return true if processing was successful, or false otherwise
685     bool processGradientUnnamedOption (SetGradientFunction* const theSetGradient = setGradient) const
686     {
687       const Standard_Integer aNumberOfGradientUnnamedOptionArguments = myCommandParser.GetNumberOfOptionArguments (
688         ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
689       if (aNumberOfGradientUnnamedOptionArguments < 2)
690       {
691         return false;
692       }
693
694       Standard_Integer anArgumentIndex = 0;
695       Quantity_Color   aColor1;
696       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor1))
697       {
698         return false;
699       }
700       if (anArgumentIndex >= aNumberOfGradientUnnamedOptionArguments)
701       {
702         return false;
703       }
704
705       Quantity_Color aColor2;
706       if (!myCommandParser.ArgColor (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, anArgumentIndex, aColor2))
707       {
708         return false;
709       }
710       if (anArgumentIndex > aNumberOfGradientUnnamedOptionArguments)
711       {
712         return false;
713       }
714
715       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
716       if (anArgumentIndex == aNumberOfGradientUnnamedOptionArguments - 1)
717       {
718         std::string anGradientModeString;
719
720         if (!myCommandParser.Arg (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY,
721                                   anArgumentIndex,
722                                   anGradientModeString))
723         {
724           return false;
725         }
726         if (!getBackgroundGradientFillMethodByName (anGradientModeString.c_str(), aGradientMode))
727         {
728           return false;
729         }
730         ++anArgumentIndex;
731       }
732       if (anArgumentIndex != aNumberOfGradientUnnamedOptionArguments)
733       {
734         return false;
735       }
736       theSetGradient (aColor1, aColor2, aGradientMode);
737       return true;
738     }
739
740     //! Processes the gradient mode unnamed option
741     //! @return true if processing was successful, or false otherwise
742     bool processGradientModeUnnamedOption() const
743     {
744       return processGradientModeOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY);
745     }
746
747     //! Processes the color unnamed option
748     //! @param theSetColor the function used to set a background color
749     //! @return true if processing was successful, or false otherwise
750     bool processColorUnnamedOption (SetColorFunction* const theSetColor = setColor) const
751     {
752       return processColorOptionSet (ViewerTest_CmdParser::THE_UNNAMED_COMMAND_OPTION_KEY, theSetColor);
753     }
754
755     //! Processes the default back unnamed option
756     //! @return true if processing was successful, or false otherwise
757     bool processDefaultUnnamedOption() const
758     {
759       if (processGradientUnnamedOption (setDefaultGradient))
760       {
761         return true;
762       }
763       return processColorUnnamedOption (setDefaultColor);
764     }
765
766     //! Processes named options
767     //! @param theBackgroundCommandName the name of the command that changes the background
768     //! @param theBackgroundCommand the key of the command that changes the background
769     //! @param theDrawInterpretor the interpreter of the Draw Harness application
770     //! @return true if processing was successful, or false otherwise
771     bool processNamedOptions (const char* const       theBackgroundCommandName,
772                               const BackgroundCommand theBackgroundCommand,
773                               Draw_Interpretor&       theDrawInterpretor) const
774     {
775       const bool                           isMain       = (theBackgroundCommand == BackgroundCommand_Main);
776       const ViewerTest_CommandOptionKeySet aUsedOptions = myCommandParser.GetUsedOptions();
777       if (myCubeMapOptionVariableSet.IsInSet (aUsedOptions) && isMain)
778       {
779         return processCubeMapOptionSet();
780       }
781       if (myImageOptionVariableSet.IsInSet (aUsedOptions)
782           && (isMain || (theBackgroundCommand == BackgroundCommand_Image)))
783       {
784         return processImageOptionSet();
785       }
786       if (myImageModeOptionVariableSet.IsInSet (aUsedOptions)
787           && (isMain || (theBackgroundCommand == BackgroundCommand_ImageMode)))
788       {
789         return processImageModeOptionSet();
790       }
791       if (myGradientOptionVariableSet.IsInSet (aUsedOptions)
792           && (isMain || (theBackgroundCommand == BackgroundCommand_Gradient)))
793       {
794         return processGradientOptionSet();
795       }
796       if (myGradientModeOptionVariableSet.IsInSet (aUsedOptions)
797           && (isMain || (theBackgroundCommand == BackgroundCommand_GradientMode)))
798       {
799         return processGradientModeOptionSet();
800       }
801       if (myColorOptionVariableSet.IsInSet (aUsedOptions)
802           && (isMain || (theBackgroundCommand == BackgroundCommand_Color)))
803       {
804         return processColorOptionSet();
805       }
806       if ((myDefaultGradientOptionVariableSet.IsInSet (aUsedOptions) && isMain)
807           || (myGradientOptionVariableSet.IsInSet (aUsedOptions)
808               && (theBackgroundCommand == BackgroundCommand_Default)))
809       {
810         return processDefaultGradientOptionSet();
811       }
812       if ((myDefaultColorOptionVariableSet.IsInSet (aUsedOptions) && isMain)
813           || (myColorOptionVariableSet.IsInSet (aUsedOptions) && (theBackgroundCommand == BackgroundCommand_Default)))
814       {
815         return processDefaultColorOptionSet();
816       }
817       if (myHelpOptionVariableSet.IsInSet (aUsedOptions))
818       {
819         return processHelpOptionSet (theBackgroundCommandName, theDrawInterpretor);
820       }
821       return false;
822     }
823
824     //! Process the cubemap option set in named and unnamed case.
825     //! @return true if processing was successful, or false otherwise
826     bool processCubeMapOptionSet() const
827     {
828       NCollection_Array1<TCollection_AsciiString> aFilePaths;
829
830       if (!processCubeMapOptions (aFilePaths))
831       {
832         return false;
833       }
834
835       Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
836
837       if (myCommandParser.HasOption (myCubeMapOrderOptionKey))
838       {
839         if (!processCubeMapOrderOptions (anOrder))
840         {
841           return false;
842         }
843       }
844
845       bool aZIsInverted = false;
846       if (myCommandParser.HasOption (myCubeMapInvertedZOptionKey))
847       {
848         if (!processCubeMapInvertedZOptionSet())
849         {
850           return false;
851         }
852         aZIsInverted = true;
853       }
854
855       setCubeMap (aFilePaths, anOrder.Validated(), aZIsInverted);
856       return true;
857     }
858
859     //! Processes the image option set
860     //! @return true if processing was successful, or false otherwise
861     bool processImageOptionSet() const
862     {
863       std::string anImageFileName;
864       if (!processImageOption (anImageFileName))
865       {
866         return false;
867       }
868       Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
869       if (myCommandParser.HasOption (myImageModeOptionKey) && !processImageModeOption (anImageMode))
870       {
871         return false;
872       }
873       setImage (anImageFileName.c_str(), anImageMode);
874       return true;
875     }
876
877     //! Processes the image mode option set
878     //! @return true if processing was successful, or false otherwise
879     bool processImageModeOptionSet() const
880     {
881       return processImageModeOptionSet (myImageModeOptionKey);
882     }
883
884     //! Processes the image mode option set
885     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
886     //! @return true if processing was successful, or false otherwise
887     bool processImageModeOptionSet (const ViewerTest_CommandOptionKey theImageModeOptionKey) const
888     {
889       Aspect_FillMethod anImageMode = Aspect_FM_NONE;
890       if (!processImageModeOption (theImageModeOptionKey, anImageMode))
891       {
892         return false;
893       }
894       setImageMode (anImageMode);
895       return true;
896     }
897
898     //! Processes the gradient option set
899     //! @param theSetGradient the function used to set a background gradient filling
900     //! @return true if processing was successful, or false otherwise
901     bool processGradientOptionSet (SetGradientFunction* const theSetGradient = setGradient) const
902     {
903       Quantity_Color aColor1;
904       Quantity_Color aColor2;
905       if (!processGradientOption (aColor1, aColor2))
906       {
907         return false;
908       }
909       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_HOR;
910       if (myCommandParser.HasOption (myGradientModeOptionKey) && !processGradientModeOption (aGradientMode))
911       {
912         return false;
913       }
914       theSetGradient (aColor1, aColor2, aGradientMode);
915       return true;
916     }
917
918     //! Processes the gradient mode option set
919     //! @return true if processing was successful, or false otherwise
920     bool processGradientModeOptionSet() const
921     {
922       return processGradientModeOptionSet (myGradientModeOptionKey);
923     }
924
925     //! Processes the gradient mode option set
926     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
927     //! @return true if processing was successful, or false otherwise
928     bool processGradientModeOptionSet (const ViewerTest_CommandOptionKey theGradientModeOptionKey) const
929     {
930       Aspect_GradientFillMethod aGradientMode = Aspect_GFM_NONE;
931       if (!processGradientModeOption (theGradientModeOptionKey, aGradientMode))
932       {
933         return false;
934       }
935       setGradientMode (aGradientMode);
936       return true;
937     }
938
939     //! Processes the color option set
940     //! @param theSetColor the function used to set a background color
941     //! @return true if processing was successful, or false otherwise
942     bool processColorOptionSet (SetColorFunction* const theSetColor = setColor) const
943     {
944       return processColorOptionSet (myColorOptionKey, theSetColor);
945     }
946
947     //! Processes the default color option set
948     //! @return true if processing was successful, or false otherwise
949     bool processDefaultGradientOptionSet() const
950     {
951       return processGradientOptionSet (setDefaultGradient);
952     }
953
954     //! Processes the default gradient option set
955     //! @return true if processing was successful, or false otherwise
956     bool processDefaultColorOptionSet() const
957     {
958       return processColorOptionSet (setDefaultColor);
959     }
960
961     //! Processes the color option set
962     //! @param theColorOptionKey the key of the option that is interpreted as a color option
963     //! @param theSetColor the function used to set a background color
964     //! @return true if processing was successful, or false otherwise
965     bool processColorOptionSet (const ViewerTest_CommandOptionKey theColorOptionKey,
966                                 SetColorFunction* const           theSetColor = setColor) const
967     {
968       Quantity_Color aColor;
969       if (!processColorOption (theColorOptionKey, aColor))
970       {
971         return false;
972       }
973       theSetColor (aColor);
974       return true;
975     }
976
977     //! Processes the help option set
978     //! @param theBackgroundCommandName the name of the command that changes the background
979     //! @param theDrawInterpretor the interpreter of the Draw Harness application
980     //! @return true if processing was successful, or false otherwise
981     bool processHelpOptionSet (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor) const
982     {
983       const Standard_Integer aNumberOfHelpOptionArguments = myCommandParser.GetNumberOfOptionArguments (
984         ViewerTest_CmdParser::THE_HELP_COMMAND_OPTION_KEY);
985       if (aNumberOfHelpOptionArguments != 0)
986       {
987         return false;
988       }
989       return printHelp (theBackgroundCommandName, theDrawInterpretor);
990     }
991
992     //! Processes the cubemap option
993     //! @param theFilePaths the array of filenames of cubemap sides
994     //! @return true if processing was successful, or false otherwise
995     bool processCubeMapOptions (NCollection_Array1<TCollection_AsciiString> &theFilePaths) const
996     {
997       const Standard_Integer aNumberOfCubeMapOptionArguments = myCommandParser.GetNumberOfOptionArguments (myCubeMapOptionKey);
998
999       if (aNumberOfCubeMapOptionArguments != 1
1000        && aNumberOfCubeMapOptionArguments != 6)
1001       {
1002         return false;
1003       }
1004
1005       theFilePaths.Resize(0, aNumberOfCubeMapOptionArguments - 1, Standard_False);
1006
1007       for (int i = 0; i < aNumberOfCubeMapOptionArguments; ++i)
1008       {
1009         std::string aCubeMapFileName;
1010         if (!myCommandParser.Arg (myCubeMapOptionKey, i, aCubeMapFileName))
1011         {
1012           return false;
1013         }
1014         theFilePaths[i] = aCubeMapFileName.c_str();
1015       }
1016
1017       return true;
1018     }
1019
1020     //! Processes the cubemap option
1021     //! @param theIsNeededToRedraw defines need of redraw after option's processing 
1022     //! @return true if processing was successful, or false otherwise
1023     bool processCubeMapInvertedZOptionSet () const
1024     {
1025       const Standard_Integer aNumberOfCubeMapZInversionOptionArguments =
1026         myCommandParser.GetNumberOfOptionArguments (myCubeMapInvertedZOptionKey);
1027
1028       if (aNumberOfCubeMapZInversionOptionArguments != 0)
1029       {
1030         return false;
1031       }
1032
1033       return true;
1034     }
1035
1036     //! Processes the tiles order option
1037     //! @param theOrder the array of indexes if cubemap sides in tile grid
1038     //! @return true if processing was successful, or false otherwise
1039     bool processCubeMapOrderOptions (Graphic3d_CubeMapOrder& theOrder) const
1040     {
1041       const Standard_Integer aNumberOfCubeMapOrderOptionArguments = myCommandParser.GetNumberOfOptionArguments(
1042         myCubeMapOrderOptionKey);
1043
1044       if (aNumberOfCubeMapOrderOptionArguments != 6)
1045       {
1046         return false;
1047       }
1048
1049
1050       for (unsigned int i = 0; i < 6; ++i)
1051       {
1052         std::string anOrderItem;
1053         if (!myCommandParser.Arg (myCubeMapOrderOptionKey, i, anOrderItem)) 
1054         {
1055           return false;
1056         }
1057
1058         theOrder.Set (Graphic3d_CubeMapSide (i),
1059                       static_cast<unsigned char> (Draw::Atoi (anOrderItem.c_str())));
1060       }
1061
1062       return theOrder.IsValid();
1063     }
1064
1065     //! Processes the image option
1066     //! @param theImageFileName the filename of the image to be used as a background
1067     //! @return true if processing was successful, or false otherwise
1068     bool processImageOption (std::string& theImageFileName) const
1069     {
1070       const Standard_Integer aNumberOfImageOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1071         myImageOptionKey);
1072       if (aNumberOfImageOptionArguments != 1)
1073       {
1074         return false;
1075       }
1076       std::string anImageFileName;
1077       if (!myCommandParser.Arg (myImageOptionKey, 0, anImageFileName))
1078       {
1079         return false;
1080       }
1081       theImageFileName = anImageFileName;
1082       return true;
1083     }
1084
1085     //! Processes the image mode option
1086     //! @param theImageMode the fill type used for a background image
1087     //! @return true if processing was successful, or false otherwise
1088     bool processImageModeOption (Aspect_FillMethod& theImageMode) const
1089     {
1090       return processImageModeOption (myImageModeOptionKey, theImageMode);
1091     }
1092
1093     //! Processes the image mode option
1094     //! @param theImageModeOptionKey the key of the option that is interpreted as an image mode option
1095     //! @param theImageMode the fill type used for a background image
1096     //! @return true if processing was successful, or false otherwise
1097     bool processImageModeOption (const ViewerTest_CommandOptionKey theImageModeOptionKey,
1098                                  Aspect_FillMethod&                theImageMode) const
1099     {
1100       return processModeOption (theImageModeOptionKey, getBackgroundImageFillMethodByName, theImageMode);
1101     }
1102
1103     //! Processes the gradient option
1104     //! @param theColor1 the gradient starting color
1105     //! @param theColor2 the gradient ending color
1106     //! @return true if processing was successful, or false otherwise
1107     bool processGradientOption (Quantity_Color& theColor1, Quantity_Color& theColor2) const
1108     {
1109       Standard_Integer anArgumentIndex = 0;
1110       Quantity_Color   aColor1;
1111       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor1))
1112       {
1113         return false;
1114       }
1115       Quantity_Color aColor2;
1116       if (!myCommandParser.ArgColor (myGradientOptionKey, anArgumentIndex, aColor2))
1117       {
1118         return false;
1119       }
1120       const Standard_Integer aNumberOfGradientOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1121         myGradientOptionKey);
1122       if (anArgumentIndex != aNumberOfGradientOptionArguments)
1123       {
1124         return false;
1125       }
1126       theColor1 = aColor1;
1127       theColor2 = aColor2;
1128       return true;
1129     }
1130
1131     //! Processes the gradient mode option
1132     //! @param theGradientMode the fill method used for a background gradient filling
1133     //! @return true if processing was successful, or false otherwise
1134     bool processGradientModeOption (Aspect_GradientFillMethod& theGradientMode) const
1135     {
1136       return processGradientModeOption (myGradientModeOptionKey, theGradientMode);
1137     }
1138
1139     //! Processes the gradient mode option
1140     //! @param theGradientModeOptionKey the key of the option that is interpreted as a gradient mode option
1141     //! @param theGradientMode the fill method used for a background gradient filling
1142     //! @return true if processing was successful, or false otherwise
1143     bool processGradientModeOption (const ViewerTest_CommandOptionKey theGradientModeOptionKey,
1144                                     Aspect_GradientFillMethod&        theGradientMode) const
1145     {
1146       return processModeOption (theGradientModeOptionKey, getBackgroundGradientFillMethodByName, theGradientMode);
1147     }
1148
1149     //! Processes some mode option
1150     //! @tparam TheMode the type of a mode to be processed
1151     //! @param theModeOptionKey the key of the option that is interpreted as a mode option
1152     //! @param theMode a mode to be processed
1153     //! @return true if processing was successful, or false otherwise
1154     template <typename TheMode>
1155     bool processModeOption (const ViewerTest_CommandOptionKey theModeOptionKey,
1156                             bool (*const theGetModeByName) (const TCollection_AsciiString& /* theModeName */,
1157                                                             TheMode& /* theMode */),
1158                             TheMode& theMode) const
1159     {
1160       const Standard_Integer aNumberOfModeOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1161         theModeOptionKey);
1162       if (aNumberOfModeOptionArguments != 1)
1163       {
1164         return false;
1165       }
1166       std::string aModeString;
1167       if (!myCommandParser.Arg (theModeOptionKey, 0, aModeString))
1168       {
1169         return false;
1170       }
1171       TheMode aMode = TheMode();
1172       if (!theGetModeByName (aModeString.c_str(), aMode))
1173       {
1174         return false;
1175       }
1176       theMode = aMode;
1177       return true;
1178     }
1179
1180     //! Processes the color option
1181     //! @param theColor a color used for filling a background
1182     //! @return true if processing was successful, or false otherwise
1183     bool processColorOption (Quantity_Color& theColor) const
1184     {
1185       return processColorOption (myColorOptionKey, theColor);
1186     }
1187
1188     //! Processes the color option
1189     //! @param theColorOptionKey the key of the option that is interpreted as a color option
1190     //! @param theColor a color used for filling a background
1191     //! @return true if processing was successful, or false otherwise
1192     bool processColorOption (const ViewerTest_CommandOptionKey theColorOptionKey, Quantity_Color& theColor) const
1193     {
1194       Standard_Integer anArgumentIndex = 0;
1195       Quantity_Color   aColor;
1196       if (!myCommandParser.ArgColor (theColorOptionKey, anArgumentIndex, aColor))
1197       {
1198         return false;
1199       }
1200       const Standard_Integer aNumberOfColorOptionArguments = myCommandParser.GetNumberOfOptionArguments (
1201         theColorOptionKey);
1202       if (anArgumentIndex != aNumberOfColorOptionArguments)
1203       {
1204         return false;
1205       }
1206       theColor = aColor;
1207       return true;
1208     }
1209
1210     //! Prints helping message
1211     //! @param theBackgroundCommandName the name of the command that changes the background
1212     //! @param theDrawInterpretor the interpreter of the Draw Harness application
1213     //! @return true if printing was successful, or false otherwise
1214     static bool printHelp (const char* const theBackgroundCommandName, Draw_Interpretor& theDrawInterpretor)
1215     {
1216       return theDrawInterpretor.PrintHelp (theBackgroundCommandName) == TCL_OK;
1217     }
1218
1219     //! Sets the cubemap as a background
1220     //! @param theFileNames the array of filenames of packed or multifile cubemap
1221     //! @param theOrder array of cubemap sides indexes mapping them from tiles in packed cubemap
1222     static void setCubeMap (const NCollection_Array1<TCollection_AsciiString>& theFileNames,
1223                             const Graphic3d_ValidatedCubeMapOrder              theOrder = Graphic3d_CubeMapOrder::Default(),
1224                             bool                                               theZIsInverted = false)
1225     {
1226       const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
1227       Handle(Graphic3d_CubeMap) aCubeMap;
1228
1229       if (theFileNames.Size() == 1)
1230         aCubeMap = new Graphic3d_CubeMapPacked(theFileNames[0], theOrder);
1231       else
1232         aCubeMap = new Graphic3d_CubeMapSeparate(theFileNames);
1233
1234       aCubeMap->SetZInversion (theZIsInverted);
1235
1236       aCubeMap->GetParams()->SetFilter(Graphic3d_TOTF_BILINEAR);
1237       aCubeMap->GetParams()->SetRepeat(Standard_False);
1238       aCubeMap->GetParams()->SetTextureUnit(Graphic3d_TextureUnit_EnvMap);
1239
1240       aCurrentView->SetBackgroundCubeMap (aCubeMap, Standard_True);
1241     }
1242
1243     //! Sets the image as a background
1244     //! @param theImageFileName the filename of the image to be used as a background
1245     //! @param theImageMode the fill type used for a background image
1246     static void setImage (const Standard_CString theImageFileName, const Aspect_FillMethod theImageMode)
1247     {
1248       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1249       aCurrentView->SetBackgroundImage (theImageFileName, theImageMode, Standard_True);
1250     }
1251
1252     //! Sets the fill type used for a background image
1253     //! @param theImageMode the fill type used for a background image
1254     static void setImageMode (const Aspect_FillMethod theImageMode)
1255     {
1256       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1257       aCurrentView->SetBgImageStyle (theImageMode, Standard_True);
1258     }
1259
1260     //! Sets the gradient filling for a background
1261     //! @param theColor1 the gradient starting color
1262     //! @param theColor2 the gradient ending color
1263     //! @param theGradientMode the fill method used for a background gradient filling
1264     static void setGradient (const Quantity_Color&           theColor1,
1265                              const Quantity_Color&           theColor2,
1266                              const Aspect_GradientFillMethod theGradientMode)
1267     {
1268       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1269       aCurrentView->SetBgGradientColors (theColor1, theColor2, theGradientMode, Standard_True);
1270     }
1271
1272     //! Sets the fill method used for a background gradient filling
1273     //! @param theGradientMode the fill method used for a background gradient filling
1274     static void setGradientMode (const Aspect_GradientFillMethod theGradientMode)
1275     {
1276       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1277       aCurrentView->SetBgGradientStyle (theGradientMode, Standard_True);
1278     }
1279
1280     //! Sets the color used for filling a background
1281     //! @param theColor the color used for filling a background
1282     static void setColor (const Quantity_Color& theColor)
1283     {
1284       const Handle (V3d_View)& aCurrentView = ViewerTest::CurrentView();
1285       aCurrentView->SetBgGradientStyle (Aspect_GFM_NONE);
1286       aCurrentView->SetBackgroundColor (theColor);
1287       aCurrentView->Update();
1288     }
1289
1290     //! Sets the gradient filling for a background in a default viewer
1291     //! @param theColor1 the gradient starting color
1292     //! @param theColor2 the gradient ending color
1293     //! @param theGradientMode the fill method used for a background gradient filling
1294     static void setDefaultGradient (const Quantity_Color&           theColor1,
1295                                     const Quantity_Color&           theColor2,
1296                                     const Aspect_GradientFillMethod theGradientMode)
1297     {
1298       ViewerTest_DefaultBackground.GradientColor1 = theColor1;
1299       ViewerTest_DefaultBackground.GradientColor2 = theColor2;
1300       ViewerTest_DefaultBackground.FillMethod     = theGradientMode;
1301       setDefaultGradient();
1302     }
1303
1304     //! Sets the color used for filling a background in a default viewer
1305     //! @param theColor the color used for filling a background
1306     static void setDefaultColor (const Quantity_Color& theColor)
1307     {
1308       ViewerTest_DefaultBackground.GradientColor1 = Quantity_Color();
1309       ViewerTest_DefaultBackground.GradientColor2 = Quantity_Color();
1310       ViewerTest_DefaultBackground.FillMethod     = Aspect_GFM_NONE;
1311       ViewerTest_DefaultBackground.FlatColor      = theColor;
1312       setDefaultGradient();
1313       setDefaultColor();
1314     }
1315
1316     //! Sets the gradient filling for a background in a default viewer.
1317     //! Gradient settings are taken from ViewerTest_DefaultBackground structure
1318     static void setDefaultGradient()
1319     {
1320       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1321              anInteractiveContextIterator (ViewerTest_myContexts);
1322            anInteractiveContextIterator.More();
1323            anInteractiveContextIterator.Next())
1324       {
1325         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1326         aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1327                                              ViewerTest_DefaultBackground.GradientColor2,
1328                                              ViewerTest_DefaultBackground.FillMethod);
1329       }
1330     }
1331
1332     //! Sets the color used for filling a background in a default viewer.
1333     //! The color value is taken from ViewerTest_DefaultBackground structure
1334     static void setDefaultColor()
1335     {
1336       for (NCollection_DoubleMap<TCollection_AsciiString, Handle (AIS_InteractiveContext)>::Iterator
1337              anInteractiveContextIterator (ViewerTest_myContexts);
1338            anInteractiveContextIterator.More();
1339            anInteractiveContextIterator.Next())
1340       {
1341         const Handle (V3d_Viewer)& aViewer = anInteractiveContextIterator.Value()->CurrentViewer();
1342         aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1343       }
1344     }
1345   };
1346
1347 } // namespace
1348
1349 //==============================================================================
1350
1351 #ifdef _WIN32
1352 static LRESULT WINAPI ViewerWindowProc(
1353                                        HWND hwnd,
1354                                        UINT uMsg,
1355                                        WPARAM wParam,
1356                                        LPARAM lParam );
1357 static LRESULT WINAPI AdvViewerWindowProc(
1358   HWND hwnd,
1359   UINT uMsg,
1360   WPARAM wParam,
1361   LPARAM lParam );
1362 #endif
1363
1364
1365 //==============================================================================
1366 //function : WClass
1367 //purpose  :
1368 //==============================================================================
1369
1370 const Handle(Standard_Transient)& ViewerTest::WClass()
1371 {
1372   static Handle(Standard_Transient) theWClass;
1373 #if defined(_WIN32)
1374   if (theWClass.IsNull())
1375   {
1376     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
1377                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
1378                                 ::LoadCursor (NULL, IDC_ARROW));
1379   }
1380 #endif
1381   return theWClass;
1382 }
1383
1384 //==============================================================================
1385 //function : CreateName
1386 //purpose  : Create numerical name for new object in theMap
1387 //==============================================================================
1388 template <typename ObjectType>
1389 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
1390                                     const TCollection_AsciiString& theDefaultString)
1391 {
1392   if (theObjectMap.IsEmpty())
1393     return theDefaultString + TCollection_AsciiString(1);
1394
1395   Standard_Integer aNextKey = 1;
1396   Standard_Boolean isFound = Standard_False;
1397   while (!isFound)
1398   {
1399     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
1400     // Look for objects with default names
1401     if (theObjectMap.IsBound1(aStringKey))
1402     {
1403       aNextKey++;
1404     }
1405     else
1406       isFound = Standard_True;
1407   }
1408
1409   return theDefaultString + TCollection_AsciiString(aNextKey);
1410 }
1411
1412 //==============================================================================
1413 //structure : ViewerTest_Names
1414 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
1415 //==============================================================================
1416 struct ViewerTest_Names
1417 {
1418 private:
1419   TCollection_AsciiString myDriverName;
1420   TCollection_AsciiString myViewerName;
1421   TCollection_AsciiString myViewName;
1422
1423 public:
1424
1425   const TCollection_AsciiString& GetDriverName () const
1426   {
1427     return myDriverName;
1428   }
1429   void SetDriverName (const TCollection_AsciiString& theDriverName)
1430   {
1431     myDriverName = theDriverName;
1432   }
1433   const TCollection_AsciiString& GetViewerName () const
1434   {
1435     return myViewerName;
1436   }
1437   void SetViewerName (const TCollection_AsciiString& theViewerName)
1438   {
1439     myViewerName = theViewerName;
1440   }
1441   const TCollection_AsciiString& GetViewName () const
1442   {
1443     return myViewName;
1444   }
1445   void SetViewName (const TCollection_AsciiString& theViewName)
1446   {
1447     myViewName = theViewName;
1448   }
1449
1450   //===========================================================================
1451   //function : Constructor for ViewerTest_Names
1452   //purpose  : Get view, viewer, driver names from custom string
1453   //===========================================================================
1454
1455   ViewerTest_Names (const TCollection_AsciiString& theInputString)
1456   {
1457     TCollection_AsciiString aName(theInputString);
1458     if (theInputString.IsEmpty())
1459     {
1460       // Get current configuration
1461       if (ViewerTest_myDrivers.IsEmpty())
1462         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1463           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1464       else
1465         myDriverName = ViewerTest_myDrivers.Find2
1466         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1467
1468       if(ViewerTest_myContexts.IsEmpty())
1469       {
1470         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1471           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1472       }
1473       else
1474       {
1475         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
1476       }
1477
1478       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
1479     }
1480     else
1481     {
1482       // There is at least view name
1483       Standard_Integer aParserNumber = 0;
1484       for (Standard_Integer i = 0; i < 3; ++i)
1485       {
1486         Standard_Integer aParserPos = aName.SearchFromEnd("/");
1487         if(aParserPos != -1)
1488         {
1489           aParserNumber++;
1490           aName.Split(aParserPos-1);
1491         }
1492         else
1493           break;
1494       }
1495       if (aParserNumber == 0)
1496       {
1497         // Only view name
1498         if (!ViewerTest::GetAISContext().IsNull())
1499         {
1500           myDriverName = ViewerTest_myDrivers.Find2
1501           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1502           myViewerName = ViewerTest_myContexts.Find2
1503           (ViewerTest::GetAISContext());
1504         }
1505         else
1506         {
1507           // There is no opened contexts here, need to create names for viewer and driver
1508           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1509             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1510
1511           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
1512             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
1513         }
1514         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
1515       }
1516       else if (aParserNumber == 1)
1517       {
1518         // Here is viewerName/viewName
1519         if (!ViewerTest::GetAISContext().IsNull())
1520           myDriverName = ViewerTest_myDrivers.Find2
1521           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
1522         else
1523         {
1524           // There is no opened contexts here, need to create name for driver
1525           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
1526             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
1527         }
1528         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
1529
1530         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
1531       }
1532       else
1533       {
1534         //Here is driverName/viewerName/viewName
1535         myDriverName = TCollection_AsciiString(aName);
1536
1537         TCollection_AsciiString aViewerName(theInputString);
1538         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
1539         myViewerName = TCollection_AsciiString(aViewerName);
1540
1541         myViewName = TCollection_AsciiString(theInputString);
1542       }
1543     }
1544   }
1545 };
1546
1547 //==============================================================================
1548 //function : FindContextByView
1549 //purpose  : Find AIS_InteractiveContext by View
1550 //==============================================================================
1551
1552 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
1553 {
1554   Handle(AIS_InteractiveContext) anAISContext;
1555
1556   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1557        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
1558   {
1559     if (anIter.Value()->CurrentViewer() == theView->Viewer())
1560        return anIter.Key2();
1561   }
1562   return anAISContext;
1563 }
1564
1565 //==============================================================================
1566 //function : IsWindowOverlapped
1567 //purpose  : Check if theWindow overlapp another view
1568 //==============================================================================
1569
1570 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
1571                                      const Standard_Integer thePxTop,
1572                                      const Standard_Integer thePxRight,
1573                                      const Standard_Integer thePxBottom,
1574                                      TCollection_AsciiString& theViewId)
1575 {
1576   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
1577       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1578   {
1579     Standard_Integer aTop = 0,
1580       aLeft = 0,
1581       aRight = 0,
1582       aBottom = 0;
1583     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
1584     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1585         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
1586         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
1587         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
1588     {
1589       theViewId = anIter.Key1();
1590       return Standard_True;
1591     }
1592   }
1593   return Standard_False;
1594 }
1595
1596 // Workaround: to create and delete non-orthographic views outside ViewerTest
1597 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
1598 {
1599   ViewerTest_myViews.UnBind1 (theName);
1600 }
1601
1602 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
1603                                const Handle(V3d_View)& theView)
1604 {
1605   ViewerTest_myViews.Bind (theName, theView);
1606 }
1607
1608 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
1609 {
1610   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
1611 }
1612
1613 //! Auxiliary tool performing continuous redraws of specified window.
1614 class ViewerTest_ContinuousRedrawer
1615 {
1616 public:
1617   //! Return global instance.
1618   static ViewerTest_ContinuousRedrawer& Instance()
1619   {
1620     static ViewerTest_ContinuousRedrawer aRedrawer;
1621     return aRedrawer;
1622   }
1623 public:
1624
1625   //! Destructor.
1626   ~ViewerTest_ContinuousRedrawer()
1627   {
1628     Stop();
1629   }
1630
1631   //! Start thread.
1632   void Start (const Handle(Aspect_Window)& theWindow,
1633               Standard_Real theTargetFps)
1634   {
1635     if (myWindow != theWindow
1636      || myTargetFps != theTargetFps)
1637     {
1638       Stop();
1639       myWindow = theWindow;
1640       myTargetFps = theTargetFps;
1641     }
1642     if (myThread.GetId() == 0)
1643     {
1644       myToStop = false;
1645       myThread.Run (this);
1646     }
1647   }
1648
1649   //! Stop thread.
1650   void Stop (const Handle(Aspect_Window)& theWindow = NULL)
1651   {
1652     if (!theWindow.IsNull()
1653       && myWindow != theWindow)
1654     {
1655       return;
1656     }
1657
1658     {
1659       Standard_Mutex::Sentry aLock (myMutex);
1660       myToStop = true;
1661     }
1662     myThread.Wait();
1663     myToStop = false;
1664     myWindow.Nullify();
1665   }
1666
1667 private:
1668
1669   //! Thread loop.
1670   void doThreadLoop()
1671   {
1672     Handle(Aspect_DisplayConnection) aDisp = new Aspect_DisplayConnection();
1673     OSD_Timer aTimer;
1674     aTimer.Start();
1675     Standard_Real aTimeOld = 0.0;
1676     const Standard_Real aTargetDur = myTargetFps > 0.0 ? 1.0 / myTargetFps : -1.0;
1677     for (;;)
1678     {
1679       {
1680         Standard_Mutex::Sentry aLock (myMutex);
1681         if (myToStop)
1682         {
1683           return;
1684         }
1685       }
1686       if (myTargetFps > 0.0)
1687       {
1688         const Standard_Real aTimeNew  = aTimer.ElapsedTime();
1689         const Standard_Real aDuration = aTimeNew - aTimeOld;
1690         if (aDuration >= aTargetDur)
1691         {
1692           myWindow->InvalidateContent (aDisp);
1693           aTimeOld = aTimeNew;
1694         }
1695       }
1696       else
1697       {
1698         myWindow->InvalidateContent (aDisp);
1699       }
1700
1701       OSD::MilliSecSleep (1);
1702     }
1703   }
1704
1705   //! Thread creation callback.
1706   static Standard_Address doThreadWrapper (Standard_Address theData)
1707   {
1708     ViewerTest_ContinuousRedrawer* aThis = (ViewerTest_ContinuousRedrawer* )theData;
1709     aThis->doThreadLoop();
1710     return 0;
1711   }
1712
1713   //! Empty constructor.
1714   ViewerTest_ContinuousRedrawer()
1715   : myThread (doThreadWrapper),
1716     myTargetFps (0.0),
1717     myToStop (false) {}
1718
1719 private:
1720   Handle(Aspect_Window) myWindow;
1721   OSD_Thread      myThread;
1722   Standard_Mutex  myMutex;
1723   Standard_Real   myTargetFps;
1724   volatile bool   myToStop;
1725 };
1726
1727 //==============================================================================
1728 //function : ViewerInit
1729 //purpose  : Create the window viewer and initialize all the global variable
1730 //==============================================================================
1731
1732 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
1733                                                 const Standard_Integer thePxTop,
1734                                                 const Standard_Integer thePxWidth,
1735                                                 const Standard_Integer thePxHeight,
1736                                                 const TCollection_AsciiString& theViewName,
1737                                                 const TCollection_AsciiString& theDisplayName,
1738                                                 const Handle(V3d_View)& theViewToClone)
1739 {
1740   // Default position and dimension of the viewer window.
1741   // Note that left top corner is set to be sufficiently small to have
1742   // window fit in the small screens (actual for remote desktops, see #23003).
1743   // The position corresponds to the window's client area, thus some
1744   // gap is added for window frame to be visible.
1745   Standard_Integer aPxLeft   = 20;
1746   Standard_Integer aPxTop    = 40;
1747   Standard_Integer aPxWidth  = 409;
1748   Standard_Integer aPxHeight = 409;
1749   Standard_Boolean toCreateViewer = Standard_False;
1750   if (!theViewToClone.IsNull())
1751   {
1752     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
1753   }
1754
1755   Handle(OpenGl_GraphicDriver) aGraphicDriver;
1756   ViewerTest_Names aViewNames(theViewName);
1757   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
1758     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
1759
1760   if (thePxLeft != 0)
1761     aPxLeft = thePxLeft;
1762   if (thePxTop != 0)
1763     aPxTop = thePxTop;
1764   if (thePxWidth != 0)
1765     aPxWidth = thePxWidth;
1766   if (thePxHeight != 0)
1767     aPxHeight = thePxHeight;
1768
1769   // Get graphic driver (create it or get from another view)
1770   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
1771   if (isNewDriver)
1772   {
1773     // Get connection string
1774   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1775     if (!theDisplayName.IsEmpty())
1776     {
1777       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
1778     }
1779     else
1780     {
1781       ::Display* aDispX = NULL;
1782       // create dedicated display connection instead of reusing Tk connection
1783       // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
1784       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
1785       Tcl_Interp* aTclInterp = aCommands.Interp();
1786       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
1787       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
1788       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
1789     }
1790   #else
1791     (void)theDisplayName; // avoid warning on unused argument
1792     SetDisplayConnection (new Aspect_DisplayConnection ());
1793   #endif
1794
1795     if (Draw_VirtualWindows)
1796     {
1797       // don't waste the time waiting for VSync when window is not displayed on the screen
1798       ViewerTest_myDefaultCaps.swapInterval = 0;
1799       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
1800       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
1801     }
1802     aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection(), false);
1803     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
1804     aGraphicDriver->InitContext();
1805
1806     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
1807     toCreateViewer = Standard_True;
1808   }
1809   else
1810   {
1811     aGraphicDriver = Handle(OpenGl_GraphicDriver)::DownCast (ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName()));
1812   }
1813
1814   //Dispose the window if input parameters are default
1815   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
1816   {
1817     Standard_Integer aTop = 0,
1818                      aLeft = 0,
1819                      aRight = 0,
1820                      aBottom = 0,
1821                      aScreenWidth = 0,
1822                      aScreenHeight = 0;
1823
1824     // Get screen resolution
1825 #if defined(_WIN32) || defined(__WIN32__)
1826     RECT aWindowSize;
1827     GetClientRect(GetDesktopWindow(), &aWindowSize);
1828     aScreenHeight = aWindowSize.bottom;
1829     aScreenWidth = aWindowSize.right;
1830 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1831     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
1832 #else
1833     Screen *aScreen = DefaultScreenOfDisplay(GetDisplayConnection()->GetDisplay());
1834     aScreenWidth = WidthOfScreen(aScreen);
1835     aScreenHeight = HeightOfScreen(aScreen);
1836 #endif
1837
1838     TCollection_AsciiString anOverlappedViewId("");
1839
1840     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
1841     {
1842       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
1843
1844       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
1845         && aRight + 2*aPxWidth + 40 > aScreenWidth)
1846       {
1847         if (aBottom + aPxHeight + 40 > aScreenHeight)
1848         {
1849           aPxLeft = 20;
1850           aPxTop = 40;
1851           break;
1852         }
1853         aPxLeft = 20;
1854         aPxTop = aBottom + 40;
1855       }
1856       else
1857         aPxLeft = aRight + 20;
1858     }
1859   }
1860
1861   // Get viewer name
1862   TCollection_AsciiString aTitle("3D View - ");
1863   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
1864
1865   // Change name of current active window
1866   if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
1867   {
1868     aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
1869   }
1870
1871   // Create viewer
1872   Handle(V3d_Viewer) a3DViewer;
1873   // If it's the single view, we first look for empty context
1874   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
1875   {
1876     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1877       anIter(ViewerTest_myContexts);
1878     if (anIter.More())
1879       ViewerTest::SetAISContext (anIter.Value());
1880     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1881   }
1882   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
1883   {
1884     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
1885     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
1886   }
1887   else if (a3DViewer.IsNull())
1888   {
1889     toCreateViewer = Standard_True;
1890     a3DViewer = new V3d_Viewer(aGraphicDriver);
1891     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
1892     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
1893                                            ViewerTest_DefaultBackground.GradientColor2,
1894                                            ViewerTest_DefaultBackground.FillMethod);
1895   }
1896
1897   // AIS context setup
1898   if (ViewerTest::GetAISContext().IsNull() ||
1899       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
1900   {
1901     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
1902     ViewerTest::SetAISContext (aContext);
1903     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
1904   }
1905   else
1906   {
1907     ViewerTest::ResetEventManager();
1908   }
1909
1910   // Create window
1911 #if defined(_WIN32)
1912   VT_GetWindow() = new WNT_Window (aTitle.ToCString(),
1913                                     Handle(WNT_WClass)::DownCast (WClass()),
1914                                     Draw_VirtualWindows ? WS_POPUP : WS_OVERLAPPEDWINDOW,
1915                                     aPxLeft, aPxTop,
1916                                     aPxWidth, aPxHeight,
1917                                     Quantity_NOC_BLACK);
1918 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1919   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
1920                                      aPxLeft, aPxTop,
1921                                      aPxWidth, aPxHeight);
1922   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
1923 #else
1924   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
1925                                   aTitle.ToCString(),
1926                                   aPxLeft, aPxTop,
1927                                   aPxWidth, aPxHeight);
1928 #endif
1929   VT_GetWindow()->SetVirtual (Draw_VirtualWindows);
1930
1931   // View setup
1932   Handle(V3d_View) aView;
1933   if (!theViewToClone.IsNull())
1934   {
1935     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
1936   }
1937   else
1938   {
1939     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
1940   }
1941
1942   aView->SetWindow (VT_GetWindow());
1943   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
1944
1945   ViewerTest::CurrentView(aView);
1946   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
1947
1948   // Setup for X11 or NT
1949   OSWindowSetup();
1950
1951   // Set parameters for V3d_View and V3d_Viewer
1952   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
1953   aV3dView->SetComputedMode(Standard_False);
1954
1955   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
1956   if (toCreateViewer)
1957   {
1958     a3DViewer->SetDefaultLights();
1959     a3DViewer->SetLightOn();
1960   }
1961
1962 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1963   if (isNewDriver)
1964   {
1965     ::Display* aDispX = GetDisplayConnection()->GetDisplay();
1966     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
1967   }
1968 #endif
1969
1970   VT_GetWindow()->Map();
1971
1972   // Set the handle of created view in the event manager
1973   ViewerTest::ResetEventManager();
1974
1975   ViewerTest::CurrentView()->Redraw();
1976
1977   aView.Nullify();
1978   a3DViewer.Nullify();
1979
1980   return aViewNames.GetViewName();
1981 }
1982
1983 //==============================================================================
1984 //function : RedrawAllViews
1985 //purpose  : Redraw all created views
1986 //==============================================================================
1987 void ViewerTest::RedrawAllViews()
1988 {
1989   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
1990   for (; aViewIt.More(); aViewIt.Next())
1991   {
1992     const Handle(V3d_View)& aView = aViewIt.Key2();
1993     aView->Redraw();
1994   }
1995 }
1996
1997 //==============================================================================
1998 //function : Vinit
1999 //purpose  : Create the window viewer and initialize all the global variable
2000 //    Use Tk_CreateFileHandler on UNIX to catch the X11 Viewer event
2001 //==============================================================================
2002
2003 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2004 {
2005   TCollection_AsciiString aViewName, aDisplayName;
2006   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
2007   Handle(V3d_View) aCopyFrom;
2008   TCollection_AsciiString aName, aValue;
2009   int is2dMode = -1;
2010   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
2011   {
2012     const TCollection_AsciiString anArg = theArgVec[anArgIt];
2013     TCollection_AsciiString anArgCase = anArg;
2014     anArgCase.LowerCase();
2015     if (anArgIt + 1 < theArgsNb
2016      && anArgCase == "-name")
2017     {
2018       aViewName = theArgVec[++anArgIt];
2019     }
2020     else if (anArgIt + 1 < theArgsNb
2021           && (anArgCase == "-left"
2022            || anArgCase == "-l"))
2023     {
2024       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
2025     }
2026     else if (anArgIt + 1 < theArgsNb
2027           && (anArgCase == "-top"
2028            || anArgCase == "-t"))
2029     {
2030       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
2031     }
2032     else if (anArgIt + 1 < theArgsNb
2033           && (anArgCase == "-width"
2034            || anArgCase == "-w"))
2035     {
2036       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
2037     }
2038     else if (anArgIt + 1 < theArgsNb
2039           && (anArgCase == "-height"
2040            || anArgCase == "-h"))
2041     {
2042       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
2043     }
2044     else if (anArgCase == "-exitonclose")
2045     {
2046       ViewerTest_EventManager::ToExitOnCloseView() = true;
2047       if (anArgIt + 1 < theArgsNb
2048        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToExitOnCloseView()))
2049       {
2050         ++anArgIt;
2051       }
2052     }
2053     else if (anArgCase == "-closeonescape"
2054           || anArgCase == "-closeonesc")
2055     {
2056       ViewerTest_EventManager::ToCloseViewOnEscape() = true;
2057       if (anArgIt + 1 < theArgsNb
2058        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], ViewerTest_EventManager::ToCloseViewOnEscape()))
2059       {
2060         ++anArgIt;
2061       }
2062     }
2063     else if (anArgCase == "-2d_mode"
2064           || anArgCase == "-2dmode"
2065           || anArgCase == "-2d")
2066     {
2067       bool toEnable = true;
2068       if (anArgIt + 1 < theArgsNb
2069        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
2070       {
2071         ++anArgIt;
2072       }
2073       is2dMode = toEnable ? 1 : 0;
2074     }
2075     else if (anArgIt + 1 < theArgsNb
2076           && (anArgCase == "-disp"
2077            || anArgCase == "-display"))
2078     {
2079       aDisplayName = theArgVec[++anArgIt];
2080     }
2081     else if (!ViewerTest::CurrentView().IsNull()
2082           &&  aCopyFrom.IsNull()
2083           && (anArgCase == "-copy"
2084            || anArgCase == "-clone"
2085            || anArgCase == "-cloneactive"
2086            || anArgCase == "-cloneactiveview"))
2087     {
2088       aCopyFrom = ViewerTest::CurrentView();
2089     }
2090     // old syntax
2091     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
2092     {
2093       aName.LowerCase();
2094       if (aName == "name")
2095       {
2096         aViewName = aValue;
2097       }
2098       else if (aName == "l"
2099             || aName == "left")
2100       {
2101         aPxLeft = aValue.IntegerValue();
2102       }
2103       else if (aName == "t"
2104             || aName == "top")
2105       {
2106         aPxTop = aValue.IntegerValue();
2107       }
2108       else if (aName == "disp"
2109             || aName == "display")
2110       {
2111         aDisplayName = aValue;
2112       }
2113       else if (aName == "w"
2114             || aName == "width")
2115       {
2116         aPxWidth = aValue.IntegerValue();
2117       }
2118       else if (aName == "h"
2119             || aName == "height")
2120       {
2121         aPxHeight = aValue.IntegerValue();
2122       }
2123       else
2124       {
2125         std::cout << "Syntax error: unknown argument " << anArg << ".\n";
2126         return 1;
2127       }
2128     }
2129     else if (aViewName.IsEmpty())
2130     {
2131       aViewName = anArg;
2132     }
2133     else
2134     {
2135       std::cout << "Syntax error: unknown argument " << anArg << ".\n";
2136       return 1;
2137     }
2138   }
2139
2140 #if defined(_WIN32) || (defined(__APPLE__) && !defined(MACOSX_USE_GLX))
2141   if (!aDisplayName.IsEmpty())
2142   {
2143     aDisplayName.Clear();
2144     std::cout << "Warning: display parameter will be ignored.\n";
2145   }
2146 #endif
2147
2148   ViewerTest_Names aViewNames (aViewName);
2149   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
2150   {
2151     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
2152     theDi.Eval (aCommand.ToCString());
2153     if (is2dMode != -1)
2154     {
2155       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2156     }
2157     return 0;
2158   }
2159
2160   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
2161                                                             aViewName, aDisplayName, aCopyFrom);
2162   if (is2dMode != -1)
2163   {
2164     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
2165   }
2166   theDi << aViewId;
2167   return 0;
2168 }
2169
2170 //! Parse HLR algo type.
2171 static Standard_Boolean parseHlrAlgoType (const char* theName,
2172                                           Prs3d_TypeOfHLR& theType)
2173 {
2174   TCollection_AsciiString aName (theName);
2175   aName.LowerCase();
2176   if (aName == "polyalgo")
2177   {
2178     theType = Prs3d_TOH_PolyAlgo;
2179   }
2180   else if (aName == "algo")
2181   {
2182     theType = Prs3d_TOH_Algo;
2183   }
2184   else
2185   {
2186     return Standard_False;
2187   }
2188   return Standard_True;
2189 }
2190
2191 //==============================================================================
2192 //function : VHLR
2193 //purpose  : hidden lines removal algorithm
2194 //==============================================================================
2195
2196 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
2197 {
2198   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2199   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2200   if (aView.IsNull())
2201   {
2202     std::cerr << "Error: No opened viewer!\n";
2203     return 1;
2204   }
2205
2206   Standard_Boolean hasHlrOnArg = Standard_False;
2207   Standard_Boolean hasShowHiddenArg = Standard_False;
2208   Standard_Boolean isHLROn = Standard_False;
2209   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
2210   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
2211   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2212   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2213   {
2214     TCollection_AsciiString anArg (argv[anArgIter]);
2215     anArg.LowerCase();
2216     if (anUpdateTool.parseRedrawMode (anArg))
2217     {
2218       continue;
2219     }
2220     else if (anArg == "-showhidden"
2221           && anArgIter + 1 < argc
2222           && ViewerTest::ParseOnOff (argv[anArgIter + 1], toShowHidden))
2223     {
2224       ++anArgIter;
2225       hasShowHiddenArg = Standard_True;
2226       continue;
2227     }
2228     else if ((anArg == "-type"
2229            || anArg == "-algo"
2230            || anArg == "-algotype")
2231           && anArgIter + 1 < argc
2232           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2233     {
2234       ++anArgIter;
2235       continue;
2236     }
2237     else if (!hasHlrOnArg
2238           && ViewerTest::ParseOnOff (argv[anArgIter], isHLROn))
2239     {
2240       hasHlrOnArg = Standard_True;
2241       continue;
2242     }
2243     // old syntax
2244     else if (!hasShowHiddenArg
2245           && ViewerTest::ParseOnOff(argv[anArgIter], toShowHidden))
2246     {
2247       hasShowHiddenArg = Standard_True;
2248       continue;
2249     }
2250     else
2251     {
2252       std::cout << "Syntax error at '" << argv[anArgIter] << "'\n";
2253       return 1;
2254     }
2255   }
2256   if (!hasHlrOnArg)
2257   {
2258     di << "HLR:        " << aView->ComputedMode() << "\n";
2259     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
2260     di << "HlrAlgo:    ";
2261     switch (aCtx->DefaultDrawer()->TypeOfHLR())
2262     {
2263       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
2264       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
2265       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
2266     }
2267     anUpdateTool.Invalidate();
2268     return 0;
2269   }
2270
2271   Standard_Boolean toRecompute = Standard_False;
2272   if (aTypeOfHLR != Prs3d_TOH_NotSet
2273    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
2274   {
2275     toRecompute = Standard_True;
2276     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2277   }
2278   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
2279   {
2280     toRecompute = Standard_True;
2281     if (toShowHidden)
2282     {
2283       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
2284     }
2285     else
2286     {
2287       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
2288     }
2289   }
2290
2291   // redisplay shapes
2292   if (aView->ComputedMode() && isHLROn && toRecompute)
2293   {
2294     AIS_ListOfInteractive aListOfShapes;
2295     aCtx->DisplayedObjects (aListOfShapes);
2296     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
2297     {
2298       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
2299       {
2300         aCtx->Redisplay (aShape, Standard_False);
2301       }
2302     }
2303   }
2304
2305   aView->SetComputedMode (isHLROn);
2306   return 0;
2307 }
2308
2309 //==============================================================================
2310 //function : VHLRType
2311 //purpose  : change type of using HLR algorithm
2312 //==============================================================================
2313
2314 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
2315 {
2316   const Handle(V3d_View) aView = ViewerTest::CurrentView();
2317   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
2318   if (aView.IsNull())
2319   {
2320     std::cerr << "Error: No opened viewer!\n";
2321     return 1;
2322   }
2323
2324   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
2325   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
2326   AIS_ListOfInteractive aListOfShapes;
2327   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
2328   {
2329     TCollection_AsciiString anArg (argv[anArgIter]);
2330     anArg.LowerCase();
2331     if (anUpdateTool.parseRedrawMode (anArg))
2332     {
2333       continue;
2334     }
2335     else if ((anArg == "-type"
2336            || anArg == "-algo"
2337            || anArg == "-algotype")
2338           && anArgIter + 1 < argc
2339           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
2340     {
2341       ++anArgIter;
2342       continue;
2343     }
2344     // old syntax
2345     else if (aTypeOfHLR == Prs3d_TOH_NotSet
2346           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
2347     {
2348       continue;
2349     }
2350     else
2351     {
2352       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
2353       TCollection_AsciiString aName (argv[anArgIter]);
2354       if (!aMap.IsBound2 (aName))
2355       {
2356         std::cout << "Syntax error: Wrong shape name '" << aName << "'.\n";
2357         return 1;
2358       }
2359
2360       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
2361       if (aShape.IsNull())
2362       {
2363         std::cout << "Syntax error: '" << aName << "' is not a shape presentation.\n";
2364         return 1;
2365       }
2366       aListOfShapes.Append (aShape);
2367       continue;
2368     }
2369   }
2370   if (aTypeOfHLR == Prs3d_TOH_NotSet)
2371   {
2372     std::cout << "Syntax error: wrong number of arguments!\n";
2373     return 1;
2374   }
2375
2376   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
2377   if (isGlobal)
2378   {
2379     aCtx->DisplayedObjects (aListOfShapes);
2380     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
2381   }
2382
2383   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
2384   {
2385     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
2386     if (aShape.IsNull())
2387     {
2388       continue;
2389     }
2390
2391     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
2392                             && aView->ComputedMode();
2393     if (!isGlobal
2394      || aShape->TypeOfHLR() != aTypeOfHLR)
2395     {
2396       aShape->SetTypeOfHLR (aTypeOfHLR);
2397     }
2398     if (toUpdateShape)
2399     {
2400       aCtx->Redisplay (aShape, Standard_False);
2401     }
2402   }
2403   return 0;
2404 }
2405
2406 //==============================================================================
2407 //function : FindViewIdByWindowHandle
2408 //purpose  : Find theView Id in the map of views by window handle
2409 //==============================================================================
2410 #if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2411 TCollection_AsciiString FindViewIdByWindowHandle (Aspect_Drawable theWindowHandle)
2412 {
2413   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
2414        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
2415   {
2416     Aspect_Drawable aWindowHandle = anIter.Value()->Window()->NativeHandle();
2417     if (aWindowHandle == theWindowHandle)
2418       return anIter.Key1();
2419   }
2420   return TCollection_AsciiString("");
2421 }
2422 #endif
2423
2424 //! Make the view active
2425 void ActivateView (const TCollection_AsciiString& theViewName,
2426                    Standard_Boolean theToUpdate = Standard_True)
2427 {
2428   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2429   if (aView.IsNull())
2430   {
2431     return;
2432   }
2433
2434   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
2435   if (!anAISContext.IsNull())
2436   {
2437     if (const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView())
2438     {
2439       aCurrentView->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (aCurrentView));
2440     }
2441
2442     ViewerTest::CurrentView (aView);
2443     ViewerTest::SetAISContext (anAISContext);
2444     aView->Window()->SetTitle (TCollection_AsciiString("3D View - ") + theViewName + "(*)");
2445 #if defined(_WIN32)
2446     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
2447 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
2448     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
2449 #else
2450     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
2451 #endif
2452     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2453     if (theToUpdate)
2454     {
2455       ViewerTest::CurrentView()->Redraw();
2456     }
2457   }
2458 }
2459
2460 //==============================================================================
2461 //function : RemoveView
2462 //purpose  :
2463 //==============================================================================
2464 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
2465                              const Standard_Boolean  theToRemoveContext)
2466 {
2467   if (!ViewerTest_myViews.IsBound2 (theView))
2468   {
2469     return;
2470   }
2471
2472   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
2473   RemoveView (aViewName, theToRemoveContext);
2474 }
2475
2476 //==============================================================================
2477 //function : RemoveView
2478 //purpose  : Close and remove view from display, clear maps if neccessary
2479 //==============================================================================
2480 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
2481 {
2482   if (!ViewerTest_myViews.IsBound1(theViewName))
2483   {
2484     std::cout << "Wrong view name\n";
2485     return;
2486   }
2487
2488   // Activate another view if it's active now
2489   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
2490   {
2491     if (ViewerTest_myViews.Extent() > 1)
2492     {
2493       TCollection_AsciiString aNewViewName;
2494       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2495            anIter.More(); anIter.Next())
2496       {
2497         if (anIter.Key1() != theViewName)
2498         {
2499           aNewViewName = anIter.Key1();
2500           break;
2501         }
2502       }
2503       ActivateView (aNewViewName);
2504     }
2505     else
2506     {
2507       VT_GetWindow().Nullify();
2508       ViewerTest::CurrentView (Handle(V3d_View)());
2509       if (isContextRemoved)
2510       {
2511         Handle(AIS_InteractiveContext) anEmptyContext;
2512         ViewerTest::SetAISContext(anEmptyContext);
2513       }
2514     }
2515   }
2516
2517   // Delete view
2518   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
2519   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
2520   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
2521   aRedrawer.Stop (aView->Window());
2522
2523   // Remove view resources
2524   ViewerTest_myViews.UnBind1(theViewName);
2525   aView->Window()->Unmap();
2526   aView->Remove();
2527
2528 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2529   XFlush (GetDisplayConnection()->GetDisplay());
2530 #endif
2531
2532   // Keep context opened only if the closed view is last to avoid
2533   // unused empty contexts
2534   if (!aCurrentContext.IsNull())
2535   {
2536     // Check if there are more difined views in the viewer
2537     aCurrentContext->CurrentViewer()->InitDefinedViews();
2538     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1) && !aCurrentContext->CurrentViewer()->MoreDefinedViews())
2539     {
2540       // Remove driver if there is no viewers that use it
2541       Standard_Boolean isRemoveDriver = Standard_True;
2542       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2543           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
2544       {
2545         if (aCurrentContext != anIter.Key2() &&
2546           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
2547         {
2548           isRemoveDriver = Standard_False;
2549           break;
2550         }
2551       }
2552
2553       aCurrentContext->RemoveAll (Standard_False);
2554       if(isRemoveDriver)
2555       {
2556         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
2557       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2558         Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
2559       #endif
2560       }
2561
2562       ViewerTest_myContexts.UnBind2(aCurrentContext);
2563     }
2564   }
2565   std::cout << "3D View - " << theViewName << " was deleted.\n";
2566   if (ViewerTest_EventManager::ToExitOnCloseView())
2567   {
2568     Draw_Interprete ("exit");
2569   }
2570 }
2571
2572 //==============================================================================
2573 //function : VClose
2574 //purpose  : Remove the view defined by its name
2575 //==============================================================================
2576
2577 static int VClose (Draw_Interpretor& /*theDi*/,
2578                    Standard_Integer  theArgsNb,
2579                    const char**      theArgVec)
2580 {
2581   NCollection_List<TCollection_AsciiString> aViewList;
2582   if (theArgsNb > 1)
2583   {
2584     TCollection_AsciiString anArg (theArgVec[1]);
2585     anArg.UpperCase();
2586     if (anArg.IsEqual ("ALL")
2587      || anArg.IsEqual ("*"))
2588     {
2589       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
2590            anIter.More(); anIter.Next())
2591       {
2592         aViewList.Append (anIter.Key1());
2593       }
2594       if (aViewList.IsEmpty())
2595       {
2596         std::cout << "No view to close\n";
2597         return 0;
2598       }
2599     }
2600     else
2601     {
2602       ViewerTest_Names aViewName (theArgVec[1]);
2603       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
2604       {
2605         std::cerr << "The view with name '" << theArgVec[1] << "' does not exist\n";
2606         return 1;
2607       }
2608       aViewList.Append (aViewName.GetViewName());
2609     }
2610   }
2611   else
2612   {
2613     // close active view
2614     if (ViewerTest::CurrentView().IsNull())
2615     {
2616       std::cerr << "No active view!\n";
2617       return 1;
2618     }
2619     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2620   }
2621
2622   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
2623   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
2624        anIter.More(); anIter.Next())
2625   {
2626     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
2627   }
2628
2629   return 0;
2630 }
2631
2632 //==============================================================================
2633 //function : VActivate
2634 //purpose  : Activate the view defined by its ID
2635 //==============================================================================
2636
2637 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2638 {
2639   if (theArgsNb == 1)
2640   {
2641     theDi.Eval("vviewlist");
2642     return 0;
2643   }
2644
2645   TCollection_AsciiString aNameString;
2646   Standard_Boolean toUpdate = Standard_True;
2647   Standard_Boolean toActivate = Standard_True;
2648   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
2649   {
2650     TCollection_AsciiString anArg (theArgVec[anArgIter]);
2651     anArg.LowerCase();
2652     if (toUpdate
2653      && anArg == "-noupdate")
2654     {
2655       toUpdate = Standard_False;
2656     }
2657     else if (toActivate
2658           && aNameString.IsEmpty()
2659           && anArg == "none")
2660     {
2661       ViewerTest::CurrentView()->Window()->SetTitle (TCollection_AsciiString ("3D View - ") + ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
2662       VT_GetWindow().Nullify();
2663       ViewerTest::CurrentView (Handle(V3d_View)());
2664       ViewerTest::ResetEventManager();
2665       theDi << theArgVec[0] << ": all views are inactive\n";
2666       toActivate = Standard_False;
2667     }
2668     else if (toActivate
2669           && aNameString.IsEmpty())
2670     {
2671       aNameString = theArgVec[anArgIter];
2672     }
2673     else
2674     {
2675       std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
2676       return 1;
2677     }
2678   }
2679
2680   if (!toActivate)
2681   {
2682     return 0;
2683   }
2684   else if (aNameString.IsEmpty())
2685   {
2686     std::cout << "Syntax error: wrong number of arguments\n";
2687     return 1;
2688   }
2689
2690   // Check if this view exists in the viewer with the driver
2691   ViewerTest_Names aViewNames (aNameString);
2692   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
2693   {
2694     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
2695     return 1;
2696   }
2697
2698   // Check if it is active already
2699   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
2700   {
2701     theDi << theArgVec[0] << ": the view is active already\n";
2702     return 0;
2703   }
2704
2705   ActivateView (aViewNames.GetViewName(), toUpdate);
2706   return 0;
2707 }
2708
2709 //==============================================================================
2710 //function : VViewList
2711 //purpose  : Print current list of views per viewer and graphic driver ID
2712 //           shared between viewers
2713 //==============================================================================
2714
2715 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
2716 {
2717   if (theArgsNb > 2)
2718   {
2719     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
2720           << "Usage: " << theArgVec[0] << " name";
2721     return 1;
2722   }
2723   if (ViewerTest_myContexts.Size() < 1)
2724     return 0;
2725
2726   Standard_Boolean isTreeView =
2727     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
2728
2729   if (isTreeView)
2730   {
2731     theDi << theArgVec[0] <<":\n";
2732   }
2733
2734   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
2735        aDriverIter.More(); aDriverIter.Next())
2736   {
2737     if (isTreeView)
2738       theDi << aDriverIter.Key1() << ":\n";
2739
2740     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
2741       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
2742     {
2743       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
2744       {
2745         if (isTreeView)
2746         {
2747           TCollection_AsciiString aContextName(aContextIter.Key1());
2748           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
2749         }
2750
2751         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
2752              aViewIter.More(); aViewIter.Next())
2753         {
2754           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
2755           {
2756             TCollection_AsciiString aViewName(aViewIter.Key1());
2757             if (isTreeView)
2758             {
2759               if (aViewIter.Value() == ViewerTest::CurrentView())
2760                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
2761               else
2762                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
2763             }
2764             else
2765             {
2766               theDi << aViewName << " ";
2767             }
2768           }
2769         }
2770       }
2771     }
2772   }
2773   return 0;
2774 }
2775
2776 //==============================================================================
2777 //function : GetMousePosition
2778 //purpose  :
2779 //==============================================================================
2780 void ViewerTest::GetMousePosition (Standard_Integer& theX,
2781                                    Standard_Integer& theY)
2782 {
2783   if (Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager())
2784   {
2785     theX = aViewCtrl->LastMousePosition().x();
2786     theY = aViewCtrl->LastMousePosition().y();
2787   }
2788 }
2789
2790 //==============================================================================
2791 //function : VViewProj
2792 //purpose  : Switch view projection
2793 //==============================================================================
2794 static int VViewProj (Draw_Interpretor& ,
2795                       Standard_Integer theNbArgs,
2796                       const char** theArgVec)
2797 {
2798   static Standard_Boolean isYup = Standard_False;
2799   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2800   if (aView.IsNull())
2801   {
2802     std::cout << "Error: no active view\n";
2803     return 1;
2804   }
2805
2806   TCollection_AsciiString aCmdName (theArgVec[0]);
2807   Standard_Boolean isGeneralCmd = Standard_False;
2808   if (aCmdName == "vfront")
2809   {
2810     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2811   }
2812   else if (aCmdName == "vback")
2813   {
2814     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2815   }
2816   else if (aCmdName == "vtop")
2817   {
2818     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2819   }
2820   else if (aCmdName == "vbottom")
2821   {
2822     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2823   }
2824   else if (aCmdName == "vleft")
2825   {
2826     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2827   }
2828   else if (aCmdName == "vright")
2829   {
2830     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2831   }
2832   else if (aCmdName == "vaxo")
2833   {
2834     aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2835   }
2836   else
2837   {
2838     isGeneralCmd = Standard_True;
2839     for (Standard_Integer anArgIter = 1; anArgIter < theNbArgs; ++anArgIter)
2840     {
2841       TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
2842       anArgCase.LowerCase();
2843       if (anArgCase == "-zup")
2844       {
2845         isYup = Standard_False;
2846       }
2847       else if (anArgCase == "-yup")
2848       {
2849         isYup = Standard_True;
2850       }
2851       else if (anArgCase == "-front"
2852             || anArgCase == "front"
2853             || anArgCase == "-f"
2854             || anArgCase == "f")
2855       {
2856         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Front : V3d_TypeOfOrientation_Zup_Front, isYup);
2857       }
2858       else if (anArgCase == "-back"
2859             || anArgCase == "back"
2860             || anArgCase == "-b"
2861             || anArgCase == "b")
2862       {
2863         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Back : V3d_TypeOfOrientation_Zup_Back, isYup);
2864       }
2865       else if (anArgCase == "-top"
2866             || anArgCase == "top"
2867             || anArgCase == "-t"
2868             || anArgCase == "t")
2869       {
2870         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Top : V3d_TypeOfOrientation_Zup_Top, isYup);
2871       }
2872       else if (anArgCase == "-bottom"
2873             || anArgCase == "bottom"
2874             || anArgCase == "-bot"
2875             || anArgCase == "bot"
2876             || anArgCase == "-b"
2877             || anArgCase == "b")
2878       {
2879         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Bottom : V3d_TypeOfOrientation_Zup_Bottom, isYup);
2880       }
2881       else if (anArgCase == "-left"
2882             || anArgCase == "left"
2883             || anArgCase == "-l"
2884             || anArgCase == "l")
2885       {
2886         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Left : V3d_TypeOfOrientation_Zup_Left, isYup);
2887       }
2888       else if (anArgCase == "-right"
2889             || anArgCase == "right"
2890             || anArgCase == "-r"
2891             || anArgCase == "r")
2892       {
2893         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_Right : V3d_TypeOfOrientation_Zup_Right, isYup);
2894       }
2895       else if (anArgCase == "-axoleft"
2896             || anArgCase == "-leftaxo"
2897             || anArgCase == "axoleft"
2898             || anArgCase == "leftaxo")
2899       {
2900         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoLeft : V3d_TypeOfOrientation_Zup_AxoLeft, isYup);
2901       }
2902       else if (anArgCase == "-axo"
2903             || anArgCase == "axo"
2904             || anArgCase == "-a"
2905             || anArgCase == "a"
2906             || anArgCase == "-axoright"
2907             || anArgCase == "-rightaxo"
2908             || anArgCase == "axoright"
2909             || anArgCase == "rightaxo")
2910       {
2911         aView->SetProj (isYup ? V3d_TypeOfOrientation_Yup_AxoRight : V3d_TypeOfOrientation_Zup_AxoRight, isYup);
2912       }
2913       else if (anArgCase == "+x")
2914       {
2915         aView->SetProj (V3d_Xpos, isYup);
2916       }
2917       else if (anArgCase == "-x")
2918       {
2919         aView->SetProj (V3d_Xneg, isYup);
2920       }
2921       else if (anArgCase == "+y")
2922       {
2923         aView->SetProj (V3d_Ypos, isYup);
2924       }
2925       else if (anArgCase == "-y")
2926       {
2927         aView->SetProj (V3d_Yneg, isYup);
2928       }
2929       else if (anArgCase == "+z")
2930       {
2931         aView->SetProj (V3d_Zpos, isYup);
2932       }
2933       else if (anArgCase == "-z")
2934       {
2935         aView->SetProj (V3d_Zneg, isYup);
2936       }
2937       else if (anArgCase == "+x+y+z")
2938       {
2939         aView->SetProj (V3d_XposYposZpos, isYup);
2940       }
2941       else if (anArgCase == "+x+y-z")
2942       {
2943         aView->SetProj (V3d_XposYposZneg, isYup);
2944       }
2945       else if (anArgCase == "+x-y+z")
2946       {
2947         aView->SetProj (V3d_XposYnegZpos, isYup);
2948       }
2949       else if (anArgCase == "+x-y-z")
2950       {
2951         aView->SetProj (V3d_XposYnegZneg, isYup);
2952       }
2953       else if (anArgCase == "-x+y+z")
2954       {
2955         aView->SetProj (V3d_XnegYposZpos, isYup);
2956       }
2957       else if (anArgCase == "-x+y-z")
2958       {
2959         aView->SetProj (V3d_XnegYposZneg, isYup);
2960       }
2961       else if (anArgCase == "-x-y+z")
2962       {
2963         aView->SetProj (V3d_XnegYnegZpos, isYup);
2964       }
2965       else if (anArgCase == "-x-y-z")
2966       {
2967         aView->SetProj (V3d_XnegYnegZneg, isYup);
2968       }
2969       else if (anArgCase == "+x+y")
2970       {
2971         aView->SetProj (V3d_XposYpos, isYup);
2972       }
2973       else if (anArgCase == "+x-y")
2974       {
2975         aView->SetProj (V3d_XposYneg, isYup);
2976       }
2977       else if (anArgCase == "-x+y")
2978       {
2979         aView->SetProj (V3d_XnegYpos, isYup);
2980       }
2981       else if (anArgCase == "-x-y")
2982       {
2983         aView->SetProj (V3d_XnegYneg, isYup);
2984       }
2985       else if (anArgCase == "+x+z")
2986       {
2987         aView->SetProj (V3d_XposZpos, isYup);
2988       }
2989       else if (anArgCase == "+x-z")
2990       {
2991         aView->SetProj (V3d_XposZneg, isYup);
2992       }
2993       else if (anArgCase == "-x+z")
2994       {
2995         aView->SetProj (V3d_XnegZpos, isYup);
2996       }
2997       else if (anArgCase == "-x-z")
2998       {
2999         aView->SetProj (V3d_XnegZneg, isYup);
3000       }
3001       else if (anArgCase == "+y+z")
3002       {
3003         aView->SetProj (V3d_YposZpos, isYup);
3004       }
3005       else if (anArgCase == "+y-z")
3006       {
3007         aView->SetProj (V3d_YposZneg, isYup);
3008       }
3009       else if (anArgCase == "-y+z")
3010       {
3011         aView->SetProj (V3d_YnegZpos, isYup);
3012       }
3013       else if (anArgCase == "-y-z")
3014       {
3015         aView->SetProj (V3d_YnegZneg, isYup);
3016       }
3017       else if (anArgIter + 1 < theNbArgs
3018             && anArgCase == "-frame"
3019             && TCollection_AsciiString (theArgVec[anArgIter + 1]).Length() == 4)
3020       {
3021         TCollection_AsciiString aFrameDef (theArgVec[++anArgIter]);
3022         aFrameDef.LowerCase();
3023         gp_Dir aRight, anUp;
3024         if (aFrameDef.Value (2) == aFrameDef.Value (4))
3025         {
3026           std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
3027           return 1;
3028         }
3029
3030         if (aFrameDef.Value (2) == 'x')
3031         {
3032           aRight = aFrameDef.Value (1) == '+' ? gp::DX() : -gp::DX();
3033         }
3034         else if (aFrameDef.Value (2) == 'y')
3035         {
3036           aRight = aFrameDef.Value (1) == '+' ? gp::DY() : -gp::DY();
3037         }
3038         else if (aFrameDef.Value (2) == 'z')
3039         {
3040           aRight = aFrameDef.Value (1) == '+' ? gp::DZ() : -gp::DZ();
3041         }
3042         else
3043         {
3044           std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
3045           return 1;
3046         }
3047
3048         if (aFrameDef.Value (4) == 'x')
3049         {
3050           anUp = aFrameDef.Value (3) == '+' ? gp::DX() : -gp::DX();
3051         }
3052         else if (aFrameDef.Value (4) == 'y')
3053         {
3054           anUp = aFrameDef.Value (3) == '+' ? gp::DY() : -gp::DY();
3055         }
3056         else if (aFrameDef.Value (4) == 'z')
3057         {
3058           anUp = aFrameDef.Value (3) == '+' ? gp::DZ() : -gp::DZ();
3059         }
3060         else
3061         {
3062           std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
3063           return 1;
3064         }
3065
3066         const Handle(Graphic3d_Camera)& aCamera = aView->Camera();
3067         const gp_Pnt anOriginVCS = aCamera->ConvertWorld2View (gp::Origin());
3068         const gp_Dir aDir = anUp.Crossed (aRight);
3069         aCamera->SetCenter (gp_Pnt (0, 0, 0));
3070         aCamera->SetDirection (aDir);
3071         aCamera->SetUp (anUp);
3072         aCamera->OrthogonalizeUp();
3073
3074         aView->Panning (anOriginVCS.X(), anOriginVCS.Y());
3075         aView->Update();
3076       }
3077       else
3078       {
3079         std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
3080         return 1;
3081       }
3082     }
3083   }
3084
3085   if (!isGeneralCmd
3086     && theNbArgs != 1)
3087   {
3088     std::cout << "Syntax error: wrong number of arguments\n";
3089     return 1;
3090   }
3091   return 0;
3092 }
3093
3094 //==============================================================================
3095 //function : VHelp
3096 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
3097 //Draw arg : No args
3098 //==============================================================================
3099
3100 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
3101 {
3102   di << "=========================\n";
3103   di << "F : FitAll\n";
3104   di << "T : TopView\n";
3105   di << "B : BottomView\n";
3106   di << "R : RightView\n";
3107   di << "L : LeftView\n";
3108   di << "A : AxonometricView\n";
3109   di << "D : ResetView\n";
3110
3111   di << "=========================\n";
3112   di << "S : Shading\n";
3113   di << "W : Wireframe\n";
3114   di << "H : HiddenLineRemoval\n";
3115   di << "U : Unset display mode\n";
3116   di << "Delete : Remove selection from viewer\n";
3117
3118   di << "=========================\n";
3119   di << "Selection mode \n";
3120   di << "0 : Shape\n";
3121   di << "1 : Vertex\n";
3122   di << "2 : Edge\n";
3123   di << "3 : Wire\n";
3124   di << "4 : Face\n";
3125   di << "5 : Shell\n";
3126   di << "6 : Solid\n";
3127   di << "7 : Compound\n";
3128
3129   di << "=========================\n";
3130   di << "< : Hilight next detected\n";
3131   di << "> : Hilight previous detected\n";
3132
3133   return 0;
3134 }
3135
3136 #ifdef _WIN32
3137
3138 static LRESULT WINAPI AdvViewerWindowProc (HWND theWinHandle,
3139                                            UINT theMsg,
3140                                            WPARAM wParam,
3141                                            LPARAM lParam )
3142 {
3143   if (ViewerTest_myViews.IsEmpty())
3144   {
3145     return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3146   }
3147
3148   switch (theMsg)
3149   {
3150     case WM_CLOSE:
3151     {
3152       // Delete view from map of views
3153       ViewerTest::RemoveView (FindViewIdByWindowHandle (theWinHandle));
3154       return 0;
3155     }
3156     case WM_ACTIVATE:
3157     {
3158       if (LOWORD(wParam) == WA_CLICKACTIVE
3159        || LOWORD(wParam) == WA_ACTIVE
3160        || ViewerTest::CurrentView().IsNull())
3161       {
3162         // Activate inactive window
3163         if (VT_GetWindow().IsNull()
3164          || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3165         {
3166           ActivateView (FindViewIdByWindowHandle (theWinHandle));
3167         }
3168       }
3169       break;
3170     }
3171     default:
3172     {
3173       return ViewerWindowProc (theWinHandle, theMsg, wParam, lParam);
3174     }
3175   }
3176   return 0;
3177 }
3178
3179 static LRESULT WINAPI ViewerWindowProc (HWND theWinHandle,
3180                                         UINT theMsg,
3181                                         WPARAM wParam,
3182                                         LPARAM lParam)
3183 {
3184   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
3185   if (aView.IsNull())
3186   {
3187     return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3188   }
3189
3190   switch (theMsg)
3191   {
3192     case WM_PAINT:
3193     {
3194       PAINTSTRUCT aPaint;
3195       BeginPaint(theWinHandle, &aPaint);
3196       EndPaint  (theWinHandle, &aPaint);
3197       ViewerTest::CurrentEventManager()->ProcessExpose();
3198       break;
3199     }
3200     case WM_SIZE:
3201     {
3202       ViewerTest::CurrentEventManager()->ProcessConfigure();
3203       break;
3204     }
3205     case WM_MOVE:
3206     case WM_MOVING:
3207     case WM_SIZING:
3208     {
3209       switch (aView->RenderingParams().StereoMode)
3210       {
3211         case Graphic3d_StereoMode_RowInterlaced:
3212         case Graphic3d_StereoMode_ColumnInterlaced:
3213         case Graphic3d_StereoMode_ChessBoard:
3214         {
3215           // track window moves to reverse stereo pair
3216           aView->MustBeResized();
3217           aView->Update();
3218           break;
3219         }
3220         default:
3221           break;
3222       }
3223       break;
3224     }
3225     case WM_KEYUP:
3226     case WM_KEYDOWN:
3227     {
3228       const Aspect_VKey aVKey = WNT_Window::VirtualKeyFromNative ((Standard_Integer )wParam);
3229       if (aVKey != Aspect_VKey_UNKNOWN)
3230       {
3231         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3232         if (theMsg == WM_KEYDOWN)
3233         {
3234           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3235         }
3236         else
3237         {
3238           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3239         }
3240         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3241       }
3242       break;
3243     }
3244     case WM_LBUTTONUP:
3245     case WM_MBUTTONUP:
3246     case WM_RBUTTONUP:
3247     case WM_LBUTTONDOWN:
3248     case WM_MBUTTONDOWN:
3249     case WM_RBUTTONDOWN:
3250     {
3251       const Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3252       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3253       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3254       switch (theMsg)
3255       {
3256         case WM_LBUTTONUP:
3257         case WM_LBUTTONDOWN:
3258           aButton = Aspect_VKeyMouse_LeftButton;
3259           break;
3260         case WM_MBUTTONUP:
3261         case WM_MBUTTONDOWN:
3262           aButton = Aspect_VKeyMouse_MiddleButton;
3263           break;
3264         case WM_RBUTTONUP:
3265         case WM_RBUTTONDOWN:
3266           aButton = Aspect_VKeyMouse_RightButton;
3267           break;
3268       }
3269       if (theMsg == WM_LBUTTONDOWN
3270        || theMsg == WM_MBUTTONDOWN
3271        || theMsg == WM_RBUTTONDOWN)
3272       {
3273         if (aButton == Aspect_VKeyMouse_LeftButton)
3274         {
3275           TheIsAnimating = Standard_False;
3276         }
3277
3278         SetFocus  (theWinHandle);
3279         SetCapture(theWinHandle);
3280         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3281       }
3282       else
3283       {
3284         ReleaseCapture();
3285         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3286       }
3287       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3288       break;
3289     }
3290     case WM_MOUSEWHEEL:
3291     {
3292       const int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
3293       const Standard_Real aDeltaF = Standard_Real(aDelta) / Standard_Real(WHEEL_DELTA);
3294       const Aspect_VKeyFlags aFlags = WNT_Window::MouseKeyFlagsFromEvent (wParam);
3295       Graphic3d_Vec2i aPos (int(short(LOWORD(lParam))), int(short(HIWORD(lParam))));
3296       POINT aCursorPnt = { aPos.x(), aPos.y() };
3297       if (ScreenToClient (theWinHandle, &aCursorPnt))
3298       {
3299         aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3300       }
3301
3302       ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3303       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3304       break;
3305     }
3306     case WM_MOUSEMOVE:
3307     {
3308       Graphic3d_Vec2i aPos (LOWORD(lParam), HIWORD(lParam));
3309       Aspect_VKeyMouse aButtons = WNT_Window::MouseButtonsFromEvent (wParam);
3310       Aspect_VKeyFlags aFlags   = WNT_Window::MouseKeyFlagsFromEvent(wParam);
3311
3312       // don't make a slide-show from input events - fetch the actual mouse cursor position
3313       CURSORINFO aCursor;
3314       aCursor.cbSize = sizeof(aCursor);
3315       if (::GetCursorInfo (&aCursor) != FALSE)
3316       {
3317         POINT aCursorPnt = { aCursor.ptScreenPos.x, aCursor.ptScreenPos.y };
3318         if (ScreenToClient (theWinHandle, &aCursorPnt))
3319         {
3320           // as we override mouse position, we need overriding also mouse state
3321           aPos.SetValues (aCursorPnt.x, aCursorPnt.y);
3322           aButtons = WNT_Window::MouseButtonsAsync();
3323           aFlags   = WNT_Window::MouseKeyFlagsAsync();
3324         }
3325       }
3326
3327       if (VT_GetWindow().IsNull()
3328       || (HWND )VT_GetWindow()->HWindow() != theWinHandle)
3329       {
3330         // mouse move events come also for inactive windows
3331         break;
3332       }
3333
3334       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3335       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), aView, true);
3336       break;
3337     }
3338     default:
3339     {
3340       return DefWindowProcW (theWinHandle, theMsg, wParam, lParam);
3341     }
3342   }
3343   return 0L;
3344 }
3345
3346 //==============================================================================
3347 //function : ViewerMainLoop
3348 //purpose  : Get a Event on the view and dispatch it
3349 //==============================================================================
3350
3351 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3352 {
3353   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
3354   if (aViewCtrl.IsNull()
3355    || theNbArgs < 4)
3356   {
3357     return 0;
3358   }
3359
3360   aViewCtrl->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3361
3362   std::cout << "Start picking\n";
3363
3364   MSG aMsg;
3365   aMsg.wParam = 1;
3366   while (aViewCtrl->ToPickPoint())
3367   {
3368     // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
3369     if (GetMessageW (&aMsg, NULL, 0, 0))
3370     {
3371       TranslateMessage (&aMsg);
3372       DispatchMessageW (&aMsg);
3373     }
3374   }
3375
3376   std::cout << "Picking done\n";
3377   return 0;
3378 }
3379
3380 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
3381
3382 int min( int a, int b )
3383 {
3384   if( a<b )
3385     return a;
3386   else
3387     return b;
3388 }
3389
3390 int max( int a, int b )
3391 {
3392   if( a>b )
3393     return a;
3394   else
3395     return b;
3396 }
3397
3398 int ViewerMainLoop (Standard_Integer theNbArgs, const char** theArgVec)
3399 {
3400   static XEvent aReport;
3401   const Standard_Boolean toPick = theNbArgs > 0;
3402   if (theNbArgs > 0)
3403   {
3404     if (ViewerTest::CurrentEventManager().IsNull())
3405     {
3406       return 0;
3407     }
3408     ViewerTest::CurrentEventManager()->StartPickPoint (theArgVec[1], theArgVec[2], theArgVec[3]);
3409   }
3410
3411   Display* aDisplay = GetDisplayConnection()->GetDisplay();
3412   XNextEvent (aDisplay, &aReport);
3413
3414   // Handle event for the chosen display connection
3415   switch (aReport.type)
3416   {
3417     case ClientMessage:
3418     {
3419       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
3420       {
3421         // Close the window
3422         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
3423         return toPick ? 0 : 1;
3424       }
3425       break;
3426     }
3427     case FocusIn:
3428     {
3429       // Activate inactive view
3430       Window aWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3431       if (aWindow != aReport.xfocus.window)
3432       {
3433         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
3434       }
3435       break;
3436     }
3437     case Expose:
3438     {
3439       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3440       if (anXWindow == aReport.xexpose.window)
3441       {
3442         ViewerTest::CurrentEventManager()->ProcessExpose();
3443       }
3444
3445       // remove all the ExposureMask and process them at once
3446       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3447       {
3448         if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
3449         {
3450           break;
3451         }
3452       }
3453
3454       break;
3455     }
3456     case ConfigureNotify:
3457     {
3458       // remove all the StructureNotifyMask and process them at once
3459       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3460       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3461       {
3462         if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
3463         {
3464           break;
3465         }
3466       }
3467
3468       if (anXWindow == aReport.xconfigure.window)
3469       {
3470         ViewerTest::CurrentEventManager()->ProcessConfigure();
3471       }
3472       break;
3473     }
3474     case KeyPress:
3475     case KeyRelease:
3476     {
3477       XKeyEvent*   aKeyEvent = (XKeyEvent* )&aReport;
3478       const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
3479       const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
3480       if (aVKey != Aspect_VKey_UNKNOWN)
3481       {
3482         const double aTimeStamp = ViewerTest::CurrentEventManager()->EventTime();
3483         if (aReport.type == KeyPress)
3484         {
3485           ViewerTest::CurrentEventManager()->KeyDown (aVKey, aTimeStamp);
3486         }
3487         else
3488         {
3489           ViewerTest::CurrentEventManager()->KeyUp (aVKey, aTimeStamp);
3490         }
3491         ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3492       }
3493       break;
3494     }
3495     case ButtonPress:
3496     case ButtonRelease:
3497     {
3498       const Graphic3d_Vec2i aPos (aReport.xbutton.x, aReport.xbutton.y);
3499       Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
3500       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
3501       if (aReport.xbutton.button == Button1)
3502       {
3503         aButton = Aspect_VKeyMouse_LeftButton;
3504       }
3505       if (aReport.xbutton.button == Button2)
3506       {
3507         aButton = Aspect_VKeyMouse_MiddleButton;
3508       }
3509       if (aReport.xbutton.button == Button3)
3510       {
3511         aButton = Aspect_VKeyMouse_RightButton;
3512       }
3513
3514       if (aReport.xbutton.state & ControlMask)
3515       {
3516         aFlags |= Aspect_VKeyFlags_CTRL;
3517       }
3518       if (aReport.xbutton.state & ShiftMask)
3519       {
3520         aFlags |= Aspect_VKeyFlags_SHIFT;
3521       }
3522       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3523       {
3524         aFlags |= Aspect_VKeyFlags_ALT;
3525       }
3526
3527       if (aReport.xbutton.button == Button4
3528        || aReport.xbutton.button == Button5)
3529       {
3530         if (aReport.type != ButtonPress)
3531         {
3532           break;
3533         }
3534
3535         const double aDeltaF = (aReport.xbutton.button == Button4 ? 1.0 : -1.0);
3536         ViewerTest::CurrentEventManager()->UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
3537       }
3538       else if (aReport.type == ButtonPress)
3539       {
3540         if (aButton == Aspect_VKeyMouse_LeftButton)
3541         {
3542           TheIsAnimating = Standard_False;
3543         }
3544         ViewerTest::CurrentEventManager()->PressMouseButton (aPos, aButton, aFlags, false);
3545       }
3546       else
3547       {
3548         ViewerTest::CurrentEventManager()->ReleaseMouseButton (aPos, aButton, aFlags, false);
3549       }
3550       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3551       break;
3552     }
3553     case MotionNotify:
3554     {
3555       Window anXWindow = !VT_GetWindow().IsNull() ? VT_GetWindow()->XWindow() : 0;
3556       if (anXWindow != aReport.xmotion.window)
3557       {
3558         break;
3559       }
3560
3561       // remove all the ButtonMotionMask and process them at once
3562       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
3563       {
3564         if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport))
3565         {
3566           break;
3567         }
3568       }
3569
3570       Graphic3d_Vec2i aPos (aReport.xmotion.x, aReport.xmotion.y);
3571       Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
3572       Aspect_VKeyFlags aFlags   = Aspect_VKeyFlags_NONE;
3573       if ((aReport.xmotion.state & Button1Mask) != 0)
3574       {
3575         aButtons |= Aspect_VKeyMouse_LeftButton;
3576       }
3577       else if ((aReport.xmotion.state & Button2Mask) != 0)
3578       {
3579         aButtons |= Aspect_VKeyMouse_MiddleButton;
3580       }
3581       else if ((aReport.xmotion.state & Button3Mask) != 0)
3582       {
3583         aButtons |= Aspect_VKeyMouse_RightButton;
3584       }
3585
3586       if (aReport.xmotion.state & ControlMask)
3587       {
3588         aFlags |= Aspect_VKeyFlags_CTRL;
3589       }
3590       if (aReport.xmotion.state & ShiftMask)
3591       {
3592         aFlags |= Aspect_VKeyFlags_SHIFT;
3593       }
3594       if (ViewerTest::CurrentEventManager()->Keys().IsKeyDown (Aspect_VKey_Alt))
3595       {
3596         aFlags |= Aspect_VKeyFlags_ALT;
3597       }
3598
3599       ViewerTest::CurrentEventManager()->UpdateMousePosition (aPos, aButtons, aFlags, false);
3600       ViewerTest::CurrentEventManager()->FlushViewEvents (ViewerTest::GetAISContext(), ViewerTest::CurrentView(), true);
3601       break;
3602     }
3603   }
3604   return (!toPick || ViewerTest::CurrentEventManager()->ToPickPoint()) ? 1 : 0;
3605 }
3606
3607 //==============================================================================
3608 //function : VProcessEvents
3609 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
3610 //==============================================================================
3611 static void VProcessEvents (ClientData theDispX, int)
3612 {
3613   Display* aDispX = (Display* )theDispX;
3614   Handle(Aspect_DisplayConnection) aDispConn;
3615   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
3616        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
3617   {
3618     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
3619     if (aDispConnTmp->GetDisplay() == aDispX)
3620     {
3621       aDispConn = aDispConnTmp;
3622       break;
3623     }
3624   }
3625   if (aDispConn.IsNull())
3626   {
3627     std::cerr << "Error: ViewerTest is unable processing messages for unknown X Display\n";
3628     return;
3629   }
3630
3631   // process new events in queue
3632   SetDisplayConnection (aDispConn);
3633   int aNbRemain = 0;
3634   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
3635   {
3636     const int anEventResult = ViewerMainLoop (0, NULL);
3637     if (anEventResult == 0)
3638     {
3639       return;
3640     }
3641
3642     aNbRemain = XPending (aDispX);
3643     if (++anEventIter >= aNbEventsMax
3644      || aNbRemain <= 0)
3645     {
3646       break;
3647     }
3648   }
3649
3650   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
3651   // it is possible that new events will arrive to queue before the end of this callback
3652   // so that either this callback should go into an infinite loop (blocking processing of other events)
3653   // or to keep unprocessed events till the next queue update (which can arrive not soon).
3654   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
3655   if (aNbRemain != 0)
3656   {
3657     XEvent aDummyEvent;
3658     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
3659     aDummyEvent.type = ClientMessage;
3660     aDummyEvent.xclient.format = 32;
3661     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
3662     XFlush (aDispX);
3663   }
3664
3665   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
3666   {
3667     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
3668   }
3669 }
3670 #endif
3671
3672 //==============================================================================
3673 //function : OSWindowSetup
3674 //purpose  : Setup for the X11 window to be able to cath the event
3675 //==============================================================================
3676
3677
3678 static void OSWindowSetup()
3679 {
3680 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
3681   // X11
3682
3683   Window  window   = VT_GetWindow()->XWindow();
3684   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
3685   Display *aDisplay = GetDisplayConnection()->GetDisplay();
3686   XSynchronize(aDisplay, 1);
3687
3688   // X11 : For keyboard on SUN
3689   XWMHints wmhints;
3690   wmhints.flags = InputHint;
3691   wmhints.input = 1;
3692
3693   XSetWMHints( aDisplay, window, &wmhints);
3694
3695   XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask | KeyReleaseMask |
3696     ButtonPressMask | ButtonReleaseMask |
3697     StructureNotifyMask |
3698     PointerMotionMask |
3699     Button1MotionMask | Button2MotionMask |
3700     Button3MotionMask | FocusChangeMask
3701     );
3702   Atom aDeleteWindowAtom = GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW);
3703   XSetWMProtocols(aDisplay, window, &aDeleteWindowAtom, 1);
3704
3705   XSynchronize(aDisplay, 0);
3706
3707 #else
3708   // _WIN32
3709 #endif
3710
3711 }
3712
3713 //==============================================================================
3714 //function : VFit
3715 //purpose  :
3716 //==============================================================================
3717
3718 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
3719 {
3720   const Handle(V3d_View) aView = ViewerTest::CurrentView();
3721   if (aView.IsNull())
3722   {
3723     std::cout << "Error: no active viewer!\n";
3724     return 1;
3725   }
3726
3727   Standard_Boolean toFit = Standard_True;
3728   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
3729   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3730   {
3731     TCollection_AsciiString anArg (theArgv[anArgIter]);
3732     anArg.LowerCase();
3733     if (anUpdateTool.parseRedrawMode (anArg))
3734     {
3735       continue;
3736     }
3737     else if (anArg == "-selected")
3738     {
3739       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
3740       toFit = Standard_False;
3741     }
3742     else
3743     {
3744       std::cout << "Syntax error at '" << anArg << "'\n";
3745     }
3746   }
3747
3748   if (toFit)
3749   {
3750     aView->FitAll (0.01, Standard_False);
3751   }
3752   return 0;
3753 }
3754
3755 //=======================================================================
3756 //function : VFitArea
3757 //purpose  : Fit view to show area located between two points
3758 //         : given in world 2D or 3D coordinates.
3759 //=======================================================================
3760 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
3761 {
3762   Handle(V3d_View) aView = ViewerTest::CurrentView();
3763   if (aView.IsNull())
3764   {
3765     std::cerr << theArgVec[0] << "Error: No active view.\n";
3766     return 1;
3767   }
3768
3769   // Parse arguments.
3770   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
3771   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
3772
3773   if (theArgNb == 5)
3774   {
3775     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3776     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3777     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
3778     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
3779   }
3780   else if (theArgNb == 7)
3781   {
3782     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3783     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3784     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
3785     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
3786     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
3787     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
3788   }
3789   else
3790   {
3791     std::cerr << theArgVec[0] << "Error: Invalid number of arguments.\n";
3792     theDI.PrintHelp(theArgVec[0]);
3793     return 1;
3794   }
3795
3796   // Convert model coordinates to view space
3797   Handle(Graphic3d_Camera) aCamera = aView->Camera();
3798   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
3799   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
3800
3801   // Determine fit area
3802   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
3803   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
3804
3805   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
3806
3807   if (aDiagonal < Precision::Confusion())
3808   {
3809     std::cerr << theArgVec[0] << "Error: view area is too small.\n";
3810     return 1;
3811   }
3812
3813   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
3814   return 0;
3815 }
3816
3817 //==============================================================================
3818 //function : VZFit
3819 //purpose  : ZFitall, no DRAW arguments
3820 //Draw arg : No args
3821 //==============================================================================
3822 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
3823 {
3824   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
3825
3826   if (aCurrentView.IsNull())
3827   {
3828     std::cout << theArgVec[0] << ": Call vinit before this command, please.\n";
3829     return 1;
3830   }
3831
3832   if (theArgsNb == 1)
3833   {
3834     aCurrentView->ZFitAll();
3835     aCurrentView->Redraw();
3836     return 0;
3837   }
3838
3839   Standard_Real aScale = 1.0;
3840
3841   if (theArgsNb >= 2)
3842   {
3843     aScale = Draw::Atoi (theArgVec[1]);
3844   }
3845
3846   aCurrentView->ZFitAll (aScale);
3847   aCurrentView->Redraw();
3848
3849   return 0;
3850 }
3851
3852 //==============================================================================
3853 //function : VRepaint
3854 //purpose  :
3855 //==============================================================================
3856 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
3857 {
3858   Handle(V3d_View) aView = ViewerTest::CurrentView();
3859   if (aView.IsNull())
3860   {
3861     std::cout << "Error: no active viewer!\n";
3862     return 1;
3863   }
3864
3865   Standard_Boolean isImmediateUpdate = Standard_False;
3866   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3867   {
3868     TCollection_AsciiString anArg (theArgVec[anArgIter]);
3869     anArg.LowerCase();
3870     if (anArg == "-immediate"
3871      || anArg == "-imm")
3872     {
3873       isImmediateUpdate = Standard_True;
3874       if (anArgIter + 1 < theArgNb
3875        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
3876       {
3877         ++anArgIter;
3878       }
3879     }
3880     else if (anArg == "-continuous"
3881           || anArg == "-cont"
3882           || anArg == "-fps"
3883           || anArg == "-framerate")
3884     {
3885       Standard_Real aFps = -1.0;
3886       if (anArgIter + 1 < theArgNb
3887        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
3888       {
3889         aFps = Draw::Atof (theArgVec[++anArgIter]);
3890       }
3891
3892       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
3893       if (Abs (aFps) >= 1.0)
3894       {
3895         aRedrawer.Start (aView->Window(), aFps);
3896       }
3897       else
3898       {
3899         aRedrawer.Stop();
3900       }
3901     }
3902     else
3903     {
3904       std::cout << "Syntax error at '" << anArg << "'\n";
3905       return 1;
3906     }
3907   }
3908
3909   if (isImmediateUpdate)
3910   {
3911     aView->RedrawImmediate();
3912   }
3913   else
3914   {
3915     aView->Redraw();
3916   }
3917   return 0;
3918 }
3919
3920 //==============================================================================
3921 //function : VClear
3922 //purpose  : Remove all the object from the viewer
3923 //Draw arg : No args
3924 //==============================================================================
3925
3926 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
3927 {
3928   Handle(V3d_View) V = ViewerTest::CurrentView();
3929   if(!V.IsNull())
3930     ViewerTest::Clear();
3931   return 0;
3932 }
3933
3934 //==============================================================================
3935 //function : VPick
3936 //purpose  :
3937 //==============================================================================
3938
3939 static int VPick (Draw_Interpretor& ,
3940                   Standard_Integer theNbArgs,
3941                   const char** theArgVec)
3942 {
3943   if (ViewerTest::CurrentView().IsNull())
3944   {
3945     return 1;
3946   }
3947
3948   if (theNbArgs < 4)
3949   {
3950     std::cout << "Syntax error: Invalid number of arguments\n";
3951     return 1;
3952   }
3953
3954   while (ViewerMainLoop (theNbArgs, theArgVec))
3955   {
3956     //
3957   }
3958
3959   return 0;
3960 }
3961
3962 namespace
3963 {
3964
3965   //! Changes the background
3966   //! @param theDrawInterpretor the interpreter of the Draw Harness application
3967   //! @param theNumberOfCommandLineArguments the number of passed command line arguments
3968   //! @param theCommandLineArguments the array of command line arguments
3969   //! @return TCL_OK if changing was successful, or TCL_ERROR otherwise
3970   static int vbackground (Draw_Interpretor&      theDrawInterpretor,
3971                           const Standard_Integer theNumberOfCommandLineArguments,
3972                           const char** const     theCommandLineArguments)
3973   {
3974     if (theNumberOfCommandLineArguments < 1)
3975     {
3976       return TCL_ERROR;
3977     }
3978     BackgroundChanger aBackgroundChanger;
3979     if (!aBackgroundChanger.ProcessCommandLine (theDrawInterpretor,
3980                                                 theNumberOfCommandLineArguments,
3981                                                 theCommandLineArguments))
3982     {
3983       theDrawInterpretor << "Wrong command arguments.\n"
3984                             "Type 'help "
3985                          << theCommandLineArguments[0] << "' for information about command options and its arguments.\n";
3986       return TCL_ERROR;
3987     }
3988     return TCL_OK;
3989   }
3990
3991 } // namespace
3992
3993 //==============================================================================
3994 //function : VScale
3995 //purpose  : View Scaling
3996 //==============================================================================
3997
3998 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3999 {
4000   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4001   if ( V3dView.IsNull() ) return 1;
4002
4003   if ( argc != 4 ) {
4004     di << argv[0] << "Invalid number of arguments\n";
4005     return 1;
4006   }
4007   V3dView->SetAxialScale( Draw::Atof(argv[1]),  Draw::Atof(argv[2]),  Draw::Atof(argv[3]) );
4008   return 0;
4009 }
4010 //==============================================================================
4011 //function : VZBuffTrihedron
4012 //purpose  :
4013 //==============================================================================
4014
4015 static int VZBuffTrihedron (Draw_Interpretor& /*theDI*/,
4016                             Standard_Integer  theArgNb,
4017                             const char**      theArgVec)
4018 {
4019   Handle(V3d_View) aView = ViewerTest::CurrentView();
4020   if (aView.IsNull())
4021   {
4022     std::cout << "Error: no active viewer!\n";
4023     return 1;
4024   }
4025
4026   ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
4027
4028   Aspect_TypeOfTriedronPosition aPosition     = Aspect_TOTP_LEFT_LOWER;
4029   V3d_TypeOfVisualization       aVisType      = V3d_ZBUFFER;
4030   Quantity_Color                aLabelsColor  = Quantity_NOC_WHITE;
4031   Quantity_Color                anArrowColorX = Quantity_NOC_RED;
4032   Quantity_Color                anArrowColorY = Quantity_NOC_GREEN;
4033   Quantity_Color                anArrowColorZ = Quantity_NOC_BLUE1;
4034   Standard_Real                 aScale        = 0.1;
4035   Standard_Real                 aSizeRatio    = 0.8;
4036   Standard_Real                 anArrowDiam   = 0.05;
4037   Standard_Integer              aNbFacets     = 12;
4038   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4039   {
4040     Standard_CString        anArg = theArgVec[anArgIter];
4041     TCollection_AsciiString aFlag (anArg);
4042     aFlag.LowerCase();
4043     if (anUpdateTool.parseRedrawMode (aFlag))
4044     {
4045       continue;
4046     }
4047     else if (aFlag == "-on")
4048     {
4049       continue;
4050     }
4051     else if (aFlag == "-off")
4052     {
4053       aView->TriedronErase();
4054       return 0;
4055     }
4056     else if (aFlag == "-pos"
4057           || aFlag == "-position"
4058           || aFlag == "-corner")
4059     {
4060       if (++anArgIter >= theArgNb)
4061       {
4062         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4063         return 1;
4064       }
4065
4066       TCollection_AsciiString aPosName (theArgVec[anArgIter]);
4067       aPosName.LowerCase();
4068       if (aPosName == "center")
4069       {
4070         aPosition = Aspect_TOTP_CENTER;
4071       }
4072       else if (aPosName == "left_lower"
4073             || aPosName == "lower_left"
4074             || aPosName == "leftlower"
4075             || aPosName == "lowerleft")
4076       {
4077         aPosition = Aspect_TOTP_LEFT_LOWER;
4078       }
4079       else if (aPosName == "left_upper"
4080             || aPosName == "upper_left"
4081             || aPosName == "leftupper"
4082             || aPosName == "upperleft")
4083       {
4084         aPosition = Aspect_TOTP_LEFT_UPPER;
4085       }
4086       else if (aPosName == "right_lower"
4087             || aPosName == "lower_right"
4088             || aPosName == "rightlower"
4089             || aPosName == "lowerright")
4090       {
4091         aPosition = Aspect_TOTP_RIGHT_LOWER;
4092       }
4093       else if (aPosName == "right_upper"
4094             || aPosName == "upper_right"
4095             || aPosName == "rightupper"
4096             || aPosName == "upperright")
4097       {
4098         aPosition = Aspect_TOTP_RIGHT_UPPER;
4099       }
4100       else
4101       {
4102         std::cerr << "Error: wrong syntax at '" << anArg << "' - unknown position '" << aPosName << "'\n";
4103         return 1;
4104       }
4105     }
4106     else if (aFlag == "-type")
4107     {
4108       if (++anArgIter >= theArgNb)
4109       {
4110         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4111         return 1;
4112       }
4113
4114       TCollection_AsciiString aTypeName (theArgVec[anArgIter]);
4115       aTypeName.LowerCase();
4116       if (aTypeName == "wireframe"
4117        || aTypeName == "wire")
4118       {
4119         aVisType = V3d_WIREFRAME;
4120       }
4121       else if (aTypeName == "zbuffer"
4122             || aTypeName == "shaded")
4123       {
4124         aVisType = V3d_ZBUFFER;
4125       }
4126       else
4127       {
4128         std::cerr << "Error: wrong syntax at '" << anArg << "' - unknown type '" << aTypeName << "'\n";
4129       }
4130     }
4131     else if (aFlag == "-scale")
4132     {
4133       if (++anArgIter >= theArgNb)
4134       {
4135         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4136         return 1;
4137       }
4138
4139       aScale = Draw::Atof (theArgVec[anArgIter]);
4140     }
4141     else if (aFlag == "-size"
4142           || aFlag == "-sizeratio")
4143     {
4144       if (++anArgIter >= theArgNb)
4145       {
4146         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4147         return 1;
4148       }
4149
4150       aSizeRatio = Draw::Atof (theArgVec[anArgIter]);
4151     }
4152     else if (aFlag == "-arrowdiam"
4153           || aFlag == "-arrowdiameter")
4154     {
4155       if (++anArgIter >= theArgNb)
4156       {
4157         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4158         return 1;
4159       }
4160
4161       anArrowDiam = Draw::Atof (theArgVec[anArgIter]);
4162     }
4163     else if (aFlag == "-nbfacets")
4164     {
4165       if (++anArgIter >= theArgNb)
4166       {
4167         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4168         return 1;
4169       }
4170
4171       aNbFacets = Draw::Atoi (theArgVec[anArgIter]);
4172     }
4173     else if (aFlag == "-colorlabel"
4174           || aFlag == "-colorlabels")
4175     {
4176       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4177                                                            theArgVec + anArgIter + 1,
4178                                                            aLabelsColor);
4179       if (aNbParsed == 0)
4180       {
4181         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4182         return 1;
4183       }
4184       anArgIter += aNbParsed;
4185     }
4186     else if (aFlag == "-colorarrowx")
4187     {
4188       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4189                                                            theArgVec + anArgIter + 1,
4190                                                            anArrowColorX);
4191       if (aNbParsed == 0)
4192       {
4193         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4194         return 1;
4195       }
4196       anArgIter += aNbParsed;
4197     }
4198     else if (aFlag == "-colorarrowy")
4199     {
4200       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4201                                                            theArgVec + anArgIter + 1,
4202                                                            anArrowColorY);
4203       if (aNbParsed == 0)
4204       {
4205         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4206         return 1;
4207       }
4208       anArgIter += aNbParsed;
4209     }
4210     else if (aFlag == "-colorarrowz")
4211     {
4212       Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - anArgIter - 1,
4213                                                            theArgVec + anArgIter + 1,
4214                                                            anArrowColorZ);
4215       if (aNbParsed == 0)
4216       {
4217         std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4218         return 1;
4219       }
4220       anArgIter += aNbParsed;
4221     }
4222     else
4223     {
4224       std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
4225       return 1;
4226     }
4227   }
4228
4229   aView->ZBufferTriedronSetup (anArrowColorX.Name(), anArrowColorY.Name(), anArrowColorZ.Name(),
4230                                aSizeRatio, anArrowDiam, aNbFacets);
4231   aView->TriedronDisplay (aPosition, aLabelsColor.Name(), aScale, aVisType);
4232   aView->ZFitAll();
4233   return 0;
4234 }
4235
4236 //==============================================================================
4237 //function : VRotate
4238 //purpose  : Camera Rotating
4239 //==============================================================================
4240
4241 static int VRotate (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgVec)
4242 {
4243   Handle(V3d_View) aView = ViewerTest::CurrentView();
4244   if (aView.IsNull())
4245   {
4246     std::cout << "No active view!\n";
4247     return 1;
4248   }
4249
4250   Standard_Boolean hasFlags = Standard_False;
4251   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
4252   {
4253     Standard_CString        anArg (theArgVec[anArgIter]);
4254     TCollection_AsciiString aFlag (anArg);
4255     aFlag.LowerCase();
4256     if (aFlag == "-mousestart"
4257      || aFlag == "-mousefrom")
4258     {
4259       hasFlags = Standard_True;
4260       if (anArgIter + 2 >= theArgNb)
4261       {
4262         std::cout << "Error: wrong syntax at '" << anArg << "'\n";
4263         return 1;
4264       }
4265
4266       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4267       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4268       aView->StartRotation (anX, anY);
4269     }
4270     else if (aFlag == "-mousemove")
4271     {
4272       hasFlags = Standard_True;
4273       if (anArgIter + 2 >= theArgNb)
4274       {
4275         std::cout << "Error: wrong syntax at '" << anArg << "'\n";
4276         return 1;
4277       }
4278
4279       Standard_Integer anX = Draw::Atoi (theArgVec[++anArgIter]);
4280       Standard_Integer anY = Draw::Atoi (theArgVec[++anArgIter]);
4281       aView->Rotation (anX, anY);
4282     }
4283     else if (theArgNb != 4
4284           && theArgNb != 7)
4285     {
4286       std::cout << "Error: wrong syntax at '" << anArg << "'\n";
4287       return 1;
4288     }
4289   }
4290
4291   if (hasFlags)
4292   {
4293     return 0;
4294   }
4295   else if (theArgNb == 4)
4296   {
4297     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4298     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4299     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4300     aView->Rotate (anAX, anAY, anAZ);
4301     return 0;
4302   }
4303   else if (theArgNb == 7)
4304   {
4305     Standard_Real anAX = Draw::Atof (theArgVec[1]);
4306     Standard_Real anAY = Draw::Atof (theArgVec[2]);
4307     Standard_Real anAZ = Draw::Atof (theArgVec[3]);
4308
4309     Standard_Real anX = Draw::Atof (theArgVec[4]);
4310     Standard_Real anY = Draw::Atof (theArgVec[5]);
4311     Standard_Real anZ = Draw::Atof (theArgVec[6]);
4312
4313     aView->Rotate (anAX, anAY, anAZ, anX, anY, anZ);
4314     return 0;
4315   }
4316
4317   std::cout << "Error: Invalid number of arguments\n";
4318   return 1;
4319 }
4320
4321 //==============================================================================
4322 //function : VZoom
4323 //purpose  : View zoom in / out (relative to current zoom)
4324 //==============================================================================
4325
4326 static int VZoom( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4327   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4328   if ( V3dView.IsNull() ) {
4329     return 1;
4330   }
4331
4332   if ( argc == 2 ) {
4333     Standard_Real coef = Draw::Atof(argv[1]);
4334     if ( coef <= 0.0 ) {
4335       di << argv[1] << "Invalid value\n";
4336       return 1;
4337     }
4338     V3dView->SetZoom( Draw::Atof(argv[1]) );
4339     return 0;
4340   } else {
4341     di << argv[0] << " Invalid number of arguments\n";
4342     return 1;
4343   }
4344 }
4345
4346 //==============================================================================
4347 //function : VPan
4348 //purpose  : View panning (in pixels)
4349 //==============================================================================
4350
4351 static int VPan( Draw_Interpretor& di, Standard_Integer argc, const char** argv ) {
4352   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
4353   if ( V3dView.IsNull() ) return 1;
4354
4355   if ( argc == 3 ) {
4356     V3dView->Pan( Draw::Atoi(argv[1]), Draw::Atoi(argv[2]) );
4357     return 0;
4358   } else {
4359     di << argv[0] << " Invalid number of arguments\n";
4360     return 1;
4361   }
4362 }
4363
4364 //==============================================================================
4365 //function : VPlace
4366 //purpose  : Place the point (in pixels) at the center of the window
4367 //==============================================================================
4368 static int VPlace (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgs)
4369 {
4370   Handle(V3d_View) aView = ViewerTest::CurrentView();
4371   if (aView.IsNull())
4372   {
4373     std::cerr << theArgs[0] << "Error: no active view." << std::endl;
4374     return 1;
4375   }
4376
4377   if (theArgNb != 3)
4378   {
4379     std::cerr << theArgs[0] << "Error: invalid number of arguments." << std::endl;
4380     return 1;
4381   }
4382
4383   aView->Place (Draw::Atoi (theArgs[1]), Draw::Atoi (theArgs[2]), aView->Scale());
4384
4385   return 0;
4386 }
4387
4388 static int VColorScale (Draw_Interpretor& theDI,
4389                         Standard_Integer  theArgNb,
4390                         const char**      theArgVec)
4391 {
4392   Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
4393   Handle(V3d_View)               aView    = ViewerTest::CurrentView();
4394   if (aContext.IsNull())
4395   {
4396     std::cout << "Error: no active view!\n";
4397     return 1;
4398   }
4399   if (theArgNb <= 1)
4400   {
4401     std::cout << "Error: wrong syntax at command '" << theArgVec[0] << "'!\n";
4402     return 1;
4403   }
4404
4405   Handle(AIS_ColorScale) aColorScale;
4406   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
4407   {
4408     // find existing object
4409     aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
4410     if (aColorScale.IsNull())
4411     {
4412       std::cout << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale!\n";
4413       return 1;
4414     }
4415   }
4416
4417   if (theArgNb <= 2)
4418   {
4419     if (aColorScale.IsNull())
4420     {
4421       std::cout << "Syntax error: colorscale with a given name does not exist.\n";
4422       return 1;
4423     }
4424
4425     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
4426           << "Min range: "            << aColorScale->GetMin() << "\n"
4427           << "Max range: "            << aColorScale->GetMax() << "\n"
4428           << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
4429           << "Text height: "          << aColorScale->GetTextHeight() << "\n"
4430           << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
4431           << "Color scale title: "    << aColorScale->GetTitle() << "\n"
4432           << "Label position: ";
4433     switch (aColorScale->GetLabelPosition())
4434     {
4435       case Aspect_TOCSP_NONE:
4436         theDI << "None\n";
4437         break;
4438       case Aspect_TOCSP_LEFT:
4439         theDI << "Left\n";
4440         break;
4441       case Aspect_TOCSP_RIGHT:
4442         theDI << "Right\n";
4443         break;
4444       case Aspect_TOCSP_CENTER:
4445         theDI << "Center\n";
4446         break;
4447     }
4448     return 0;
4449   }
4450
4451   if (aColorScale.IsNull())
4452   {
4453     aColorScale = new AIS_ColorScale();
4454     aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
4455     aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
4456   }
4457
4458   ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
4459   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
4460   {
4461     Standard_CString        anArg = theArgVec[anArgIter];
4462     TCollection_AsciiString aFlag (anArg);
4463     aFlag.LowerCase();
4464     if (anUpdateTool.parseRedrawMode (aFlag))
4465     {
4466       continue;
4467     }
4468     else if (aFlag == "-range")
4469     {
4470       if (anArgIter + 3 >= theArgNb)
4471       {
4472         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
4473         return 1;
4474       }
4475
4476       const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
4477       const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
4478       const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
4479       if (!aRangeMin.IsRealValue()
4480        || !aRangeMax.IsRealValue())
4481       {
4482         std::cout << "Error: the range values should be real!\n";
4483         return 1;
4484       }
4485       else if (!aNbIntervals.IsIntegerValue())
4486       {
4487         std::cout << "Error: the number of intervals should be integer!\n";
4488         return 1;
4489       }
4490
4491       aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
4492       aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
4493     }
4494     else if (aFlag == "-font")
4495     {
4496       if (anArgIter + 1 >= theArgNb)
4497       {
4498         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
4499         return 1;
4500       }
4501       TCollection_AsciiString aFontArg(theArgVec[anArgIter + 1]);
4502       if (!aFontArg.IsIntegerValue())
4503       {
4504         std::cout << "Error: HeightFont value should be integer!\n";
4505         return 1;
4506       }
4507
4508       aColorScale->SetTextHeight (aFontArg.IntegerValue());
4509       anArgIter += 1;
4510     }
4511     else if (aFlag == "-textpos")
4512     {
4513       if (anArgIter + 1 >= theArgNb)
4514       {
4515         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
4516         return 1;
4517       }
4518
4519       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
4520       aTextPosArg.LowerCase();
4521       Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
4522       if (aTextPosArg == "none")
4523       {
4524         aLabPosition = Aspect_TOCSP_NONE;
4525       }
4526       else if (aTextPosArg == "left")
4527       {
4528         aLabPosition = Aspect_TOCSP_LEFT;
4529       }
4530       else if (aTextPosArg == "right")
4531       {
4532         aLabPosition = Aspect_TOCSP_RIGHT;
4533       }
4534       else if (aTextPosArg == "center")
4535       {
4536         aLabPosition = Aspect_TOCSP_CENTER;
4537       }
4538       else
4539       {
4540         std::cout << "Error: unknown position '" << aTextPosArg << "'!\n";
4541         return 1;
4542       }
4543       aColorScale->SetLabelPosition (aLabPosition);
4544     }
4545     else if (aFlag == "-logarithmic"
4546           || aFlag == "-log")
4547     {
4548       if (anArgIter + 1 >= theArgNb)
4549       {
4550         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
4551         return 1;
4552       }
4553
4554       Standard_Boolean IsLog;
4555       if (!ViewerTest::ParseOnOff(theArgVec[++anArgIter], IsLog))
4556       {
4557         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
4558         return 1;
4559       }
4560       aColorScale->SetLogarithmic (IsLog);
4561     }
4562     else if (aFlag == "-huerange"
4563           || aFlag == "-hue")
4564     {
4565       if (anArgIter + 2 >= theArgNb)
4566       {
4567         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
4568         return 1;
4569       }
4570
4571       const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);