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