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