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