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