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