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