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