0030619: Draw Harness, ViewerTest - add continuous rendering option to vrepaint command
[occt.git] / src / ViewerTest / ViewerTest_ViewerCommands.cxx
1 // Created on: 1998-09-01
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <OpenGl_GlCore20.hxx>
18
19 #include <AIS_Animation.hxx>
20 #include <AIS_AnimationCamera.hxx>
21 #include <AIS_AnimationObject.hxx>
22 #include <AIS_CameraFrustum.hxx>
23 #include <AIS_ColorScale.hxx>
24 #include <AIS_Manipulator.hxx>
25 #include <AIS_RubberBand.hxx>
26 #include <AIS_Shape.hxx>
27 #include <AIS_InteractiveObject.hxx>
28 #include <AIS_ListOfInteractive.hxx>
29 #include <AIS_ListIteratorOfListOfInteractive.hxx>
30 #include <Aspect_Grid.hxx>
31 #include <DBRep.hxx>
32 #include <Draw_ProgressIndicator.hxx>
33 #include <Graphic3d_ArrayOfPolylines.hxx>
34 #include <Graphic3d_AspectMarker3d.hxx>
35 #include <Graphic3d_NameOfTextureEnv.hxx>
36 #include <Graphic3d_GraduatedTrihedron.hxx>
37 #include <Graphic3d_TextureEnv.hxx>
38 #include <Graphic3d_TextureParams.hxx>
39 #include <Graphic3d_TypeOfTextureFilter.hxx>
40 #include <Graphic3d_AspectFillArea3d.hxx>
41 #include <ViewerTest.hxx>
42 #include <ViewerTest_AutoUpdater.hxx>
43 #include <ViewerTest_EventManager.hxx>
44 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
45 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
46 #include <ViewerTest_CmdParser.hxx>
47 #include <V3d_AmbientLight.hxx>
48 #include <V3d_DirectionalLight.hxx>
49 #include <V3d_PositionalLight.hxx>
50 #include <V3d_SpotLight.hxx>
51 #include <Message_ProgressSentry.hxx>
52 #include <NCollection_DoubleMap.hxx>
53 #include <NCollection_List.hxx>
54 #include <NCollection_Vector.hxx>
55 #include <AIS_InteractiveContext.hxx>
56 #include <Draw_Interpretor.hxx>
57 #include <Draw.hxx>
58 #include <Draw_Appli.hxx>
59 #include <Image_AlienPixMap.hxx>
60 #include <Image_VideoRecorder.hxx>
61 #include <OpenGl_GraphicDriver.hxx>
62 #include <OSD.hxx>
63 #include <OSD_Timer.hxx>
64 #include <TColStd_HSequenceOfAsciiString.hxx>
65 #include <TColStd_SequenceOfInteger.hxx>
66 #include <TColStd_HSequenceOfReal.hxx>
67 #include <TColgp_Array1OfPnt2d.hxx>
68 #include <TColStd_MapOfAsciiString.hxx>
69 #include <Aspect_TypeOfLine.hxx>
70 #include <Image_Diff.hxx>
71 #include <Aspect_DisplayConnection.hxx>
72 #include <gp_Pnt.hxx>
73 #include <gp_Dir.hxx>
74 #include <gp_Pln.hxx>
75 #include <PrsMgr_PresentableObject.hxx>
76 #include <Graphic3d_ClipPlane.hxx>
77 #include <NCollection_DataMap.hxx>
78 #include <Graphic3d_Texture2Dmanual.hxx>
79 #include <Prs3d_ShadingAspect.hxx>
80 #include <Prs3d_Drawer.hxx>
81 #include <Prs3d_LineAspect.hxx>
82 #include <Prs3d_Root.hxx>
83 #include <Prs3d_Text.hxx>
84 #include <Select3D_SensitivePrimitiveArray.hxx>
85
86 #ifdef _WIN32
87 #undef DrawText
88 #endif
89
90 #include <cstdlib>
91
92 #if defined(_WIN32)
93   #include <WNT_WClass.hxx>
94   #include <WNT_Window.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 // Auxiliary definitions
105 static const char THE_KEY_DELETE = 127;
106 static const char THE_KEY_ESCAPE = 27;
107
108 //==============================================================================
109 //  VIEWER GLOBAL VARIABLES
110 //==============================================================================
111
112 Standard_IMPORT Standard_Boolean Draw_VirtualWindows;
113 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
114
115 Standard_EXPORT int ViewerMainLoop(Standard_Integer , const char** argv);
116 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
117
118 extern int VErase (Draw_Interpretor& theDI,
119                    Standard_Integer  theArgNb,
120                    const char**      theArgVec);
121
122 #if defined(_WIN32)
123 static Handle(WNT_Window)& VT_GetWindow() {
124   static Handle(WNT_Window) WNTWin;
125   return WNTWin;
126 }
127 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
128 static Handle(Cocoa_Window)& VT_GetWindow()
129 {
130   static Handle(Cocoa_Window) aWindow;
131   return aWindow;
132 }
133 extern void ViewerTest_SetCocoaEventManagerView (const Handle(Cocoa_Window)& theWindow);
134 extern void SetCocoaWindowTitle (const Handle(Cocoa_Window)& theWindow, Standard_CString theTitle);
135 extern void GetCocoaScreenResolution (Standard_Integer& theWidth, Standard_Integer& theHeight);
136
137 #else
138 static Handle(Xw_Window)& VT_GetWindow(){
139   static Handle(Xw_Window) XWWin;
140   return XWWin;
141 }
142
143 static void VProcessEvents(ClientData,int);
144 #endif
145
146 static Handle(Aspect_DisplayConnection)& GetDisplayConnection()
147 {
148   static Handle(Aspect_DisplayConnection) aDisplayConnection;
149   return aDisplayConnection;
150 }
151
152 static void SetDisplayConnection (const Handle(Aspect_DisplayConnection)& theDisplayConnection)
153 {
154   GetDisplayConnection() = theDisplayConnection;
155 }
156
157 #if defined(_WIN32) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
158 Aspect_Handle GetWindowHandle(const Handle(Aspect_Window)& theWindow)
159 {
160   Aspect_Handle aWindowHandle = (Aspect_Handle)NULL;
161 #if defined(_WIN32)
162   const Handle (WNT_Window) aWindow = Handle(WNT_Window)::DownCast (theWindow);
163   if (!aWindow.IsNull())
164     return aWindow->HWindow();
165 #elif (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
166   const Handle (Xw_Window) aWindow = Handle(Xw_Window)::DownCast (theWindow);
167   if (!aWindow.IsNull())
168   return aWindow->XWindow();
169 #endif
170   return aWindowHandle;
171 }
172 #endif
173
174 //! Setting additional flag to store 2D mode of the View to avoid scene rotation by mouse/key events
175 class ViewerTest_V3dView : public V3d_View
176 {
177   DEFINE_STANDARD_RTTI_INLINE(ViewerTest_V3dView, V3d_View)
178 public:
179   //! Initializes the view.
180   ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, const V3d_TypeOfView theType = V3d_ORTHOGRAPHIC,
181                       bool theIs2dMode = false)
182   : V3d_View (theViewer, theType), myIs2dMode (theIs2dMode) {}
183
184   //! Initializes the view by copying.
185   ViewerTest_V3dView (const Handle(V3d_Viewer)& theViewer, const Handle(V3d_View)& theView)
186   : V3d_View (theViewer, theView), myIs2dMode (false)
187   {
188     if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (theView))
189     {
190       myIs2dMode = aV3dView->IsViewIn2DMode();
191     }
192   }
193
194   //! Returns true if 2D mode is set for the view
195   bool IsViewIn2DMode() const { return myIs2dMode; }
196
197   //! Sets 2D mode for the view
198   void SetView2DMode (bool the2dMode) { myIs2dMode = the2dMode; }
199
200 public:
201
202   //! Returns true if active view in 2D mode.
203   static bool IsCurrentViewIn2DMode()
204   {
205     if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView()))
206     {
207       return aV3dView->IsViewIn2DMode();
208     }
209     return false;
210   }
211
212   //! Set if active view in 2D mode.
213   static void SetCurrentView2DMode (bool theIs2d)
214   {
215     if (Handle(ViewerTest_V3dView) aV3dView = Handle(ViewerTest_V3dView)::DownCast (ViewerTest::CurrentView()))
216     {
217       aV3dView->SetView2DMode (theIs2d);
218     }
219   }
220
221 private:
222
223   Standard_Boolean myIs2dMode; //!< 2D mode flag
224
225 };
226
227 NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)> ViewerTest_myViews;
228 static NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>  ViewerTest_myContexts;
229 static NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)> ViewerTest_myDrivers;
230 static OpenGl_Caps ViewerTest_myDefaultCaps;
231
232 static void OSWindowSetup();
233
234 static struct
235 {
236   Quantity_Color FlatColor;
237   Quantity_Color GradientColor1;
238   Quantity_Color GradientColor2;
239   Aspect_GradientFillMethod FillMethod;
240 } ViewerTest_DefaultBackground = { Quantity_NOC_BLACK, Quantity_NOC_BLACK, Quantity_NOC_BLACK, Aspect_GFM_NONE };
241
242 //==============================================================================
243 //  EVENT GLOBAL VARIABLES
244 //==============================================================================
245
246 static int Start_Rot = 0;
247 Standard_Boolean HasHlrOnBeforeRotation = Standard_False;
248 int X_Motion = 0; // Current cursor position
249 int Y_Motion = 0;
250 int X_ButtonPress = 0; // Last ButtonPress position
251 int Y_ButtonPress = 0;
252 Standard_Boolean IsDragged = Standard_False;
253 Standard_Boolean DragFirst = Standard_False;
254 Standard_Boolean TheIsAnimating = Standard_False;
255 Standard_Boolean Draw_ToExitOnCloseView = Standard_False;
256 Standard_Boolean Draw_ToCloseViewOnEsc  = Standard_False;
257
258
259 Standard_EXPORT const Handle(AIS_RubberBand)& GetRubberBand()
260 {
261   static Handle(AIS_RubberBand) aBand;
262   if (aBand.IsNull())
263   {
264     aBand = new AIS_RubberBand (Quantity_NOC_LIGHTBLUE, Aspect_TOL_SOLID, Quantity_NOC_LIGHTBLUE, 0.4, 1.0);
265     aBand->SetDisplayMode (0);
266   }
267   return aBand;
268 }
269
270 typedef NCollection_Map<AIS_Manipulator*> ViewerTest_MapOfAISManipulators;
271
272 Standard_EXPORT ViewerTest_MapOfAISManipulators& GetMapOfAISManipulators()
273 {
274   static ViewerTest_MapOfAISManipulators aMap;
275   return aMap;
276 }
277
278 Standard_EXPORT Handle(AIS_Manipulator) GetActiveAISManipulator()
279 {
280   ViewerTest_MapOfAISManipulators::Iterator anIt (GetMapOfAISManipulators());
281   for (; anIt.More(); anIt.Next())
282   {
283     if (anIt.Value()->HasActiveMode())
284     {
285       return anIt.Value();
286     }
287   }
288   return NULL;
289 }
290
291 //==============================================================================
292
293 #ifdef _WIN32
294 static LRESULT WINAPI ViewerWindowProc(
295                                        HWND hwnd,
296                                        UINT uMsg,
297                                        WPARAM wParam,
298                                        LPARAM lParam );
299 static LRESULT WINAPI AdvViewerWindowProc(
300   HWND hwnd,
301   UINT uMsg,
302   WPARAM wParam,
303   LPARAM lParam );
304 #endif
305
306
307 //==============================================================================
308 //function : WClass
309 //purpose  :
310 //==============================================================================
311
312 const Handle(Standard_Transient)& ViewerTest::WClass()
313 {
314   static Handle(Standard_Transient) theWClass;
315 #if defined(_WIN32)
316   if (theWClass.IsNull())
317   {
318     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
319                                 CS_VREDRAW | CS_HREDRAW, 0, 0,
320                                 ::LoadCursor (NULL, IDC_ARROW));
321   }
322 #endif
323   return theWClass;
324 }
325
326 //==============================================================================
327 //function : CreateName
328 //purpose  : Create numerical name for new object in theMap
329 //==============================================================================
330 template <typename ObjectType>
331 TCollection_AsciiString CreateName (const NCollection_DoubleMap <TCollection_AsciiString, ObjectType>& theObjectMap,
332                                     const TCollection_AsciiString& theDefaultString)
333 {
334   if (theObjectMap.IsEmpty())
335     return theDefaultString + TCollection_AsciiString(1);
336
337   Standard_Integer aNextKey = 1;
338   Standard_Boolean isFound = Standard_False;
339   while (!isFound)
340   {
341     TCollection_AsciiString aStringKey = theDefaultString + TCollection_AsciiString(aNextKey);
342     // Look for objects with default names
343     if (theObjectMap.IsBound1(aStringKey))
344     {
345       aNextKey++;
346     }
347     else
348       isFound = Standard_True;
349   }
350
351   return theDefaultString + TCollection_AsciiString(aNextKey);
352 }
353
354 //==============================================================================
355 //structure : ViewerTest_Names
356 //purpose   : Allow to operate with full view name: driverName/viewerName/viewName
357 //==============================================================================
358 struct ViewerTest_Names
359 {
360 private:
361   TCollection_AsciiString myDriverName;
362   TCollection_AsciiString myViewerName;
363   TCollection_AsciiString myViewName;
364
365 public:
366
367   const TCollection_AsciiString& GetDriverName () const
368   {
369     return myDriverName;
370   }
371   void SetDriverName (const TCollection_AsciiString& theDriverName)
372   {
373     myDriverName = theDriverName;
374   }
375   const TCollection_AsciiString& GetViewerName () const
376   {
377     return myViewerName;
378   }
379   void SetViewerName (const TCollection_AsciiString& theViewerName)
380   {
381     myViewerName = theViewerName;
382   }
383   const TCollection_AsciiString& GetViewName () const
384   {
385     return myViewName;
386   }
387   void SetViewName (const TCollection_AsciiString& theViewName)
388   {
389     myViewName = theViewName;
390   }
391
392   //===========================================================================
393   //function : Constructor for ViewerTest_Names
394   //purpose  : Get view, viewer, driver names from custom string
395   //===========================================================================
396
397   ViewerTest_Names (const TCollection_AsciiString& theInputString)
398   {
399     TCollection_AsciiString aName(theInputString);
400     if (theInputString.IsEmpty())
401     {
402       // Get current configuration
403       if (ViewerTest_myDrivers.IsEmpty())
404         myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
405           (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
406       else
407         myDriverName = ViewerTest_myDrivers.Find2
408         (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
409
410       if(ViewerTest_myContexts.IsEmpty())
411       {
412         myViewerName = CreateName <Handle(AIS_InteractiveContext)>
413           (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
414       }
415       else
416       {
417         myViewerName = ViewerTest_myContexts.Find2 (ViewerTest::GetAISContext());
418       }
419
420       myViewName = CreateName <Handle(V3d_View)> (ViewerTest_myViews, TCollection_AsciiString(myViewerName + "/View"));
421     }
422     else
423     {
424       // There is at least view name
425       Standard_Integer aParserNumber = 0;
426       for (Standard_Integer i = 0; i < 3; ++i)
427       {
428         Standard_Integer aParserPos = aName.SearchFromEnd("/");
429         if(aParserPos != -1)
430         {
431           aParserNumber++;
432           aName.Split(aParserPos-1);
433         }
434         else
435           break;
436       }
437       if (aParserNumber == 0)
438       {
439         // Only view name
440         if (!ViewerTest::GetAISContext().IsNull())
441         {
442           myDriverName = ViewerTest_myDrivers.Find2
443           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
444           myViewerName = ViewerTest_myContexts.Find2
445           (ViewerTest::GetAISContext());
446         }
447         else
448         {
449           // There is no opened contexts here, need to create names for viewer and driver
450           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
451             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
452
453           myViewerName = CreateName <Handle(AIS_InteractiveContext)>
454             (ViewerTest_myContexts, TCollection_AsciiString (myDriverName + "/Viewer"));
455         }
456         myViewName = TCollection_AsciiString(myViewerName + "/" + theInputString);
457       }
458       else if (aParserNumber == 1)
459       {
460         // Here is viewerName/viewName
461         if (!ViewerTest::GetAISContext().IsNull())
462           myDriverName = ViewerTest_myDrivers.Find2
463           (ViewerTest::GetAISContext()->CurrentViewer()->Driver());
464         else
465         {
466           // There is no opened contexts here, need to create name for driver
467           myDriverName = CreateName<Handle(Graphic3d_GraphicDriver)>
468             (ViewerTest_myDrivers, TCollection_AsciiString("Driver"));
469         }
470         myViewerName = TCollection_AsciiString(myDriverName + "/" + aName);
471
472         myViewName = TCollection_AsciiString(myDriverName + "/" + theInputString);
473       }
474       else
475       {
476         //Here is driverName/viewerName/viewName
477         myDriverName = TCollection_AsciiString(aName);
478
479         TCollection_AsciiString aViewerName(theInputString);
480         aViewerName.Split(aViewerName.SearchFromEnd("/") - 1);
481         myViewerName = TCollection_AsciiString(aViewerName);
482
483         myViewName = TCollection_AsciiString(theInputString);
484       }
485     }
486   }
487 };
488
489 //==============================================================================
490 //function : FindContextByView
491 //purpose  : Find AIS_InteractiveContext by View
492 //==============================================================================
493
494 Handle(AIS_InteractiveContext) FindContextByView (const Handle(V3d_View)& theView)
495 {
496   Handle(AIS_InteractiveContext) anAISContext;
497
498   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
499        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
500   {
501     if (anIter.Value()->CurrentViewer() == theView->Viewer())
502        return anIter.Key2();
503   }
504   return anAISContext;
505 }
506
507
508 //==============================================================================
509 //function : SetWindowTitle
510 //purpose  : Set window title
511 //==============================================================================
512
513 void SetWindowTitle (const Handle(Aspect_Window)& theWindow,
514                      Standard_CString theTitle)
515 {
516 #if defined(_WIN32)
517   const TCollection_ExtendedString theTitleW (theTitle);
518   SetWindowTextW ((HWND )Handle(WNT_Window)::DownCast(theWindow)->HWindow(), theTitleW.ToWideString());
519 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
520   SetCocoaWindowTitle (Handle(Cocoa_Window)::DownCast(theWindow), theTitle);
521 #else
522   if(GetDisplayConnection()->GetDisplay())
523   {
524     Window aWindow =
525       Handle(Xw_Window)::DownCast(theWindow)->XWindow();
526     XStoreName (GetDisplayConnection()->GetDisplay(), aWindow , theTitle);
527   }
528 #endif
529 }
530
531 //==============================================================================
532 //function : IsWindowOverlapped
533 //purpose  : Check if theWindow overlapp another view
534 //==============================================================================
535
536 Standard_Boolean IsWindowOverlapped (const Standard_Integer thePxLeft,
537                                      const Standard_Integer thePxTop,
538                                      const Standard_Integer thePxRight,
539                                      const Standard_Integer thePxBottom,
540                                      TCollection_AsciiString& theViewId)
541 {
542   for(NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator
543       anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
544   {
545     Standard_Integer aTop = 0,
546       aLeft = 0,
547       aRight = 0,
548       aBottom = 0;
549     anIter.Value()->Window()->Position(aLeft, aTop, aRight, aBottom);
550     if ((thePxLeft >= aLeft && thePxLeft <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
551         (thePxLeft >= aLeft && thePxLeft <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom) ||
552         (thePxRight >= aLeft && thePxRight <= aRight && thePxTop >= aTop && thePxTop <= aBottom) ||
553         (thePxRight >= aLeft && thePxRight <= aRight && thePxBottom >= aTop && thePxBottom <= aBottom))
554     {
555       theViewId = anIter.Key1();
556       return Standard_True;
557     }
558   }
559   return Standard_False;
560 }
561
562 // Workaround: to create and delete non-orthographic views outside ViewerTest
563 void ViewerTest::RemoveViewName (const TCollection_AsciiString& theName)
564 {
565   ViewerTest_myViews.UnBind1 (theName);
566 }
567
568 void ViewerTest::InitViewName (const TCollection_AsciiString& theName,
569                                const Handle(V3d_View)& theView)
570 {
571   ViewerTest_myViews.Bind (theName, theView);
572 }
573
574 TCollection_AsciiString ViewerTest::GetCurrentViewName ()
575 {
576   return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
577 }
578
579 //! Auxiliary tool performing continuous redraws of specified window.
580 class ViewerTest_ContinuousRedrawer
581 {
582 public:
583   //! Return global instance.
584   static ViewerTest_ContinuousRedrawer& Instance()
585   {
586     static ViewerTest_ContinuousRedrawer aRedrawer;
587     return aRedrawer;
588   }
589 public:
590
591   //! Destructor.
592   ~ViewerTest_ContinuousRedrawer()
593   {
594     Stop();
595   }
596
597   //! Start thread.
598   void Start (const Handle(Aspect_Window)& theWindow,
599               Standard_Real theTargetFps)
600   {
601     if (myWindow != theWindow
602      || myTargetFps != theTargetFps)
603     {
604       Stop();
605       myWindow = theWindow;
606       myTargetFps = theTargetFps;
607     }
608     if (myThread.GetId() == 0)
609     {
610       myToStop = false;
611       myThread.Run (this);
612     }
613   }
614
615   //! Stop thread.
616   void Stop (const Handle(Aspect_Window)& theWindow = NULL)
617   {
618     if (!theWindow.IsNull()
619       && myWindow != theWindow)
620     {
621       return;
622     }
623
624     {
625       Standard_Mutex::Sentry aLock (myMutex);
626       myToStop = true;
627     }
628     myThread.Wait();
629     myToStop = false;
630     myWindow.Nullify();
631   }
632
633 private:
634
635   //! Thread loop.
636   void doThreadLoop()
637   {
638     Handle(Aspect_DisplayConnection) aDisp = new Aspect_DisplayConnection();
639     OSD_Timer aTimer;
640     aTimer.Start();
641     Standard_Real aTimeOld = 0.0;
642     const Standard_Real aTargetDur = myTargetFps > 0.0 ? 1.0 / myTargetFps : -1.0;
643     for (;;)
644     {
645       {
646         Standard_Mutex::Sentry aLock (myMutex);
647         if (myToStop)
648         {
649           return;
650         }
651       }
652       if (myTargetFps > 0.0)
653       {
654         const Standard_Real aTimeNew  = aTimer.ElapsedTime();
655         const Standard_Real aDuration = aTimeNew - aTimeOld;
656         if (aDuration >= aTargetDur)
657         {
658           myWindow->InvalidateContent (aDisp);
659           aTimeOld = aTimeNew;
660         }
661       }
662       else
663       {
664         myWindow->InvalidateContent (aDisp);
665       }
666
667       OSD::MilliSecSleep (1);
668     }
669   }
670
671   //! Thread creation callback.
672   static Standard_Address doThreadWrapper (Standard_Address theData)
673   {
674     ViewerTest_ContinuousRedrawer* aThis = (ViewerTest_ContinuousRedrawer* )theData;
675     aThis->doThreadLoop();
676     return 0;
677   }
678
679   //! Empty constructor.
680   ViewerTest_ContinuousRedrawer()
681   : myThread (doThreadWrapper),
682     myTargetFps (0.0),
683     myToStop (false) {}
684
685 private:
686   Handle(Aspect_Window) myWindow;
687   OSD_Thread      myThread;
688   Standard_Mutex  myMutex;
689   Standard_Real   myTargetFps;
690   volatile bool   myToStop;
691 };
692
693 //==============================================================================
694 //function : ViewerInit
695 //purpose  : Create the window viewer and initialize all the global variable
696 //==============================================================================
697
698 TCollection_AsciiString ViewerTest::ViewerInit (const Standard_Integer thePxLeft,
699                                                 const Standard_Integer thePxTop,
700                                                 const Standard_Integer thePxWidth,
701                                                 const Standard_Integer thePxHeight,
702                                                 const TCollection_AsciiString& theViewName,
703                                                 const TCollection_AsciiString& theDisplayName,
704                                                 const Handle(V3d_View)& theViewToClone)
705 {
706   // Default position and dimension of the viewer window.
707   // Note that left top corner is set to be sufficiently small to have
708   // window fit in the small screens (actual for remote desktops, see #23003).
709   // The position corresponds to the window's client area, thus some
710   // gap is added for window frame to be visible.
711   Standard_Integer aPxLeft   = 20;
712   Standard_Integer aPxTop    = 40;
713   Standard_Integer aPxWidth  = 409;
714   Standard_Integer aPxHeight = 409;
715   Standard_Boolean toCreateViewer = Standard_False;
716   if (!theViewToClone.IsNull())
717   {
718     theViewToClone->Window()->Size (aPxWidth, aPxHeight);
719   }
720
721   Handle(OpenGl_GraphicDriver) aGraphicDriver;
722   ViewerTest_Names aViewNames(theViewName);
723   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName ()))
724     aViewNames.SetViewName (aViewNames.GetViewerName() + "/" + CreateName<Handle(V3d_View)>(ViewerTest_myViews, "View"));
725
726   if (thePxLeft != 0)
727     aPxLeft = thePxLeft;
728   if (thePxTop != 0)
729     aPxTop = thePxTop;
730   if (thePxWidth != 0)
731     aPxWidth = thePxWidth;
732   if (thePxHeight != 0)
733     aPxHeight = thePxHeight;
734
735   // Get graphic driver (create it or get from another view)
736   const bool isNewDriver = !ViewerTest_myDrivers.IsBound1 (aViewNames.GetDriverName());
737   if (isNewDriver)
738   {
739     // Get connection string
740   #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
741     if (!theDisplayName.IsEmpty())
742     {
743       SetDisplayConnection (new Aspect_DisplayConnection (theDisplayName));
744     }
745     else
746     {
747       ::Display* aDispX = NULL;
748       // create dedicated display connection instead of reusing Tk connection
749       // so that to procede events independently through VProcessEvents()/ViewerMainLoop() callbacks
750       /*Draw_Interpretor& aCommands = Draw::GetInterpretor();
751       Tcl_Interp* aTclInterp = aCommands.Interp();
752       Tk_Window aMainWindow = Tk_MainWindow (aTclInterp);
753       aDispX = aMainWindow != NULL ? Tk_Display (aMainWindow) : NULL;*/
754       SetDisplayConnection (new Aspect_DisplayConnection (aDispX));
755     }
756   #else
757     (void)theDisplayName; // avoid warning on unused argument
758     SetDisplayConnection (new Aspect_DisplayConnection ());
759   #endif
760
761     if (Draw_VirtualWindows)
762     {
763       // don't waste the time waiting for VSync when window is not displayed on the screen
764       ViewerTest_myDefaultCaps.swapInterval = 0;
765       // alternatively we can disable buffer swap at all, but this might be inappropriate for testing
766       //ViewerTest_myDefaultCaps.buffersNoSwap = true;
767     }
768     aGraphicDriver = new OpenGl_GraphicDriver (GetDisplayConnection());
769     aGraphicDriver->ChangeOptions() = ViewerTest_myDefaultCaps;
770
771     ViewerTest_myDrivers.Bind (aViewNames.GetDriverName(), aGraphicDriver);
772     toCreateViewer = Standard_True;
773   }
774   else
775   {
776     aGraphicDriver = Handle(OpenGl_GraphicDriver)::DownCast (ViewerTest_myDrivers.Find1 (aViewNames.GetDriverName()));
777   }
778
779   //Dispose the window if input parameters are default
780   if (!ViewerTest_myViews.IsEmpty() && thePxLeft == 0 && thePxTop == 0)
781   {
782     Standard_Integer aTop = 0,
783                      aLeft = 0,
784                      aRight = 0,
785                      aBottom = 0,
786                      aScreenWidth = 0,
787                      aScreenHeight = 0;
788
789     // Get screen resolution
790 #if defined(_WIN32) || defined(__WIN32__)
791     RECT aWindowSize;
792     GetClientRect(GetDesktopWindow(), &aWindowSize);
793     aScreenHeight = aWindowSize.bottom;
794     aScreenWidth = aWindowSize.right;
795 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
796     GetCocoaScreenResolution (aScreenWidth, aScreenHeight);
797 #else
798     Screen *aScreen = DefaultScreenOfDisplay(GetDisplayConnection()->GetDisplay());
799     aScreenWidth = WidthOfScreen(aScreen);
800     aScreenHeight = HeightOfScreen(aScreen);
801 #endif
802
803     TCollection_AsciiString anOverlappedViewId("");
804
805     while (IsWindowOverlapped (aPxLeft, aPxTop, aPxLeft + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId))
806     {
807       ViewerTest_myViews.Find1(anOverlappedViewId)->Window()->Position (aLeft, aTop, aRight, aBottom);
808
809       if (IsWindowOverlapped (aRight + 20, aPxTop, aRight + 20 + aPxWidth, aPxTop + aPxHeight, anOverlappedViewId)
810         && aRight + 2*aPxWidth + 40 > aScreenWidth)
811       {
812         if (aBottom + aPxHeight + 40 > aScreenHeight)
813         {
814           aPxLeft = 20;
815           aPxTop = 40;
816           break;
817         }
818         aPxLeft = 20;
819         aPxTop = aBottom + 40;
820       }
821       else
822         aPxLeft = aRight + 20;
823     }
824   }
825
826   // Get viewer name
827   TCollection_AsciiString aTitle("3D View - ");
828   aTitle = aTitle + aViewNames.GetViewName() + "(*)";
829
830   // Change name of current active window
831   if (!ViewerTest::CurrentView().IsNull())
832   {
833     TCollection_AsciiString anActiveWindowTitle("3D View - ");
834     anActiveWindowTitle = anActiveWindowTitle
835       + ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
836     SetWindowTitle (ViewerTest::CurrentView()->Window(), anActiveWindowTitle.ToCString());
837   }
838
839   // Create viewer
840   Handle(V3d_Viewer) a3DViewer;
841   // If it's the single view, we first look for empty context
842   if (ViewerTest_myViews.IsEmpty() && !ViewerTest_myContexts.IsEmpty())
843   {
844     NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
845       anIter(ViewerTest_myContexts);
846     if (anIter.More())
847       ViewerTest::SetAISContext (anIter.Value());
848     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
849   }
850   else if (ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName()))
851   {
852     ViewerTest::SetAISContext(ViewerTest_myContexts.Find1(aViewNames.GetViewerName()));
853     a3DViewer = ViewerTest::GetAISContext()->CurrentViewer();
854   }
855   else if (a3DViewer.IsNull())
856   {
857     toCreateViewer = Standard_True;
858     a3DViewer = new V3d_Viewer(aGraphicDriver);
859     a3DViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
860     a3DViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
861                                            ViewerTest_DefaultBackground.GradientColor2,
862                                            ViewerTest_DefaultBackground.FillMethod);
863   }
864
865   // AIS context setup
866   if (ViewerTest::GetAISContext().IsNull() ||
867       !(ViewerTest_myContexts.IsBound1(aViewNames.GetViewerName())))
868   {
869     Handle(AIS_InteractiveContext) aContext = new AIS_InteractiveContext (a3DViewer);
870     ViewerTest::SetAISContext (aContext);
871     ViewerTest_myContexts.Bind (aViewNames.GetViewerName(), ViewerTest::GetAISContext());
872   }
873   else
874   {
875     ViewerTest::ResetEventManager();
876   }
877
878   // Create window
879 #if defined(_WIN32)
880   VT_GetWindow() = new WNT_Window (aTitle.ToCString(),
881                                     Handle(WNT_WClass)::DownCast (WClass()),
882                                     Draw_VirtualWindows ? WS_POPUP : WS_OVERLAPPEDWINDOW,
883                                     aPxLeft, aPxTop,
884                                     aPxWidth, aPxHeight,
885                                     Quantity_NOC_BLACK);
886 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
887   VT_GetWindow() = new Cocoa_Window (aTitle.ToCString(),
888                                      aPxLeft, aPxTop,
889                                      aPxWidth, aPxHeight);
890   ViewerTest_SetCocoaEventManagerView (VT_GetWindow());
891 #else
892   VT_GetWindow() = new Xw_Window (aGraphicDriver->GetDisplayConnection(),
893                                   aTitle.ToCString(),
894                                   aPxLeft, aPxTop,
895                                   aPxWidth, aPxHeight);
896 #endif
897   VT_GetWindow()->SetVirtual (Draw_VirtualWindows);
898
899   // View setup
900   Handle(V3d_View) aView;
901   if (!theViewToClone.IsNull())
902   {
903     aView = new ViewerTest_V3dView (a3DViewer, theViewToClone);
904   }
905   else
906   {
907     aView = new ViewerTest_V3dView (a3DViewer, a3DViewer->DefaultTypeOfView());
908   }
909
910   aView->SetWindow (VT_GetWindow());
911   ViewerTest::GetAISContext()->RedrawImmediate (a3DViewer);
912
913   ViewerTest::CurrentView(aView);
914   ViewerTest_myViews.Bind (aViewNames.GetViewName(), aView);
915
916   // Setup for X11 or NT
917   OSWindowSetup();
918
919   // Set parameters for V3d_View and V3d_Viewer
920   const Handle (V3d_View) aV3dView = ViewerTest::CurrentView();
921   aV3dView->SetComputedMode(Standard_False);
922
923   a3DViewer->SetDefaultBackgroundColor(Quantity_NOC_BLACK);
924   if (toCreateViewer)
925   {
926     a3DViewer->SetDefaultLights();
927     a3DViewer->SetLightOn();
928   }
929
930 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
931   if (isNewDriver)
932   {
933     ::Display* aDispX = GetDisplayConnection()->GetDisplay();
934     Tcl_CreateFileHandler (XConnectionNumber (aDispX), TCL_READABLE, VProcessEvents, (ClientData )aDispX);
935   }
936 #endif
937
938   VT_GetWindow()->Map();
939
940   // Set the handle of created view in the event manager
941   ViewerTest::ResetEventManager();
942
943   ViewerTest::CurrentView()->Redraw();
944
945   aView.Nullify();
946   a3DViewer.Nullify();
947
948   return aViewNames.GetViewName();
949 }
950
951 //==============================================================================
952 //function : RedrawAllViews
953 //purpose  : Redraw all created views
954 //==============================================================================
955 void ViewerTest::RedrawAllViews()
956 {
957   NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIt(ViewerTest_myViews);
958   for (; aViewIt.More(); aViewIt.Next())
959   {
960     const Handle(V3d_View)& aView = aViewIt.Key2();
961     aView->Redraw();
962   }
963 }
964
965 //==============================================================================
966 //function : Vinit
967 //purpose  : Create the window viewer and initialize all the global variable
968 //    Use Tk_CreateFileHandler on UNIX to catch the X11 Viewer event
969 //==============================================================================
970
971 static int VInit (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
972 {
973   TCollection_AsciiString aViewName, aDisplayName;
974   Standard_Integer aPxLeft = 0, aPxTop = 0, aPxWidth = 0, aPxHeight = 0;
975   Handle(V3d_View) aCopyFrom;
976   TCollection_AsciiString aName, aValue;
977   int is2dMode = -1;
978   for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
979   {
980     const TCollection_AsciiString anArg = theArgVec[anArgIt];
981     TCollection_AsciiString anArgCase = anArg;
982     anArgCase.LowerCase();
983     if (anArgIt + 1 < theArgsNb
984      && anArgCase == "-name")
985     {
986       aViewName = theArgVec[++anArgIt];
987     }
988     else if (anArgIt + 1 < theArgsNb
989           && (anArgCase == "-left"
990            || anArgCase == "-l"))
991     {
992       aPxLeft = Draw::Atoi (theArgVec[++anArgIt]);
993     }
994     else if (anArgIt + 1 < theArgsNb
995           && (anArgCase == "-top"
996            || anArgCase == "-t"))
997     {
998       aPxTop = Draw::Atoi (theArgVec[++anArgIt]);
999     }
1000     else if (anArgIt + 1 < theArgsNb
1001           && (anArgCase == "-width"
1002            || anArgCase == "-w"))
1003     {
1004       aPxWidth = Draw::Atoi (theArgVec[++anArgIt]);
1005     }
1006     else if (anArgIt + 1 < theArgsNb
1007           && (anArgCase == "-height"
1008            || anArgCase == "-h"))
1009     {
1010       aPxHeight = Draw::Atoi (theArgVec[++anArgIt]);
1011     }
1012     else if (anArgCase == "-exitonclose")
1013     {
1014       Draw_ToExitOnCloseView = true;
1015       if (anArgIt + 1 < theArgsNb
1016        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], Draw_ToExitOnCloseView))
1017       {
1018         ++anArgIt;
1019       }
1020     }
1021     else if (anArgCase == "-closeonescape"
1022           || anArgCase == "-closeonesc")
1023     {
1024       Draw_ToCloseViewOnEsc = true;
1025       if (anArgIt + 1 < theArgsNb
1026        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], Draw_ToCloseViewOnEsc))
1027       {
1028         ++anArgIt;
1029       }
1030     }
1031     else if (anArgCase == "-2d_mode"
1032           || anArgCase == "-2dmode"
1033           || anArgCase == "-2d")
1034     {
1035       bool toEnable = true;
1036       if (anArgIt + 1 < theArgsNb
1037        && ViewerTest::ParseOnOff (theArgVec[anArgIt + 1], toEnable))
1038       {
1039         ++anArgIt;
1040       }
1041       is2dMode = toEnable ? 1 : 0;
1042     }
1043     else if (anArgIt + 1 < theArgsNb
1044           && (anArgCase == "-disp"
1045            || anArgCase == "-display"))
1046     {
1047       aDisplayName = theArgVec[++anArgIt];
1048     }
1049     else if (!ViewerTest::CurrentView().IsNull()
1050           &&  aCopyFrom.IsNull()
1051           && (anArgCase == "-copy"
1052            || anArgCase == "-clone"
1053            || anArgCase == "-cloneactive"
1054            || anArgCase == "-cloneactiveview"))
1055     {
1056       aCopyFrom = ViewerTest::CurrentView();
1057     }
1058     // old syntax
1059     else if (ViewerTest::SplitParameter (anArg, aName, aValue))
1060     {
1061       aName.LowerCase();
1062       if (aName == "name")
1063       {
1064         aViewName = aValue;
1065       }
1066       else if (aName == "l"
1067             || aName == "left")
1068       {
1069         aPxLeft = aValue.IntegerValue();
1070       }
1071       else if (aName == "t"
1072             || aName == "top")
1073       {
1074         aPxTop = aValue.IntegerValue();
1075       }
1076       else if (aName == "disp"
1077             || aName == "display")
1078       {
1079         aDisplayName = aValue;
1080       }
1081       else if (aName == "w"
1082             || aName == "width")
1083       {
1084         aPxWidth = aValue.IntegerValue();
1085       }
1086       else if (aName == "h"
1087             || aName == "height")
1088       {
1089         aPxHeight = aValue.IntegerValue();
1090       }
1091       else
1092       {
1093         std::cout << "Syntax error: unknown argument " << anArg << ".\n";
1094         return 1;
1095       }
1096     }
1097     else if (aViewName.IsEmpty())
1098     {
1099       aViewName = anArg;
1100     }
1101     else
1102     {
1103       std::cout << "Syntax error: unknown argument " << anArg << ".\n";
1104       return 1;
1105     }
1106   }
1107
1108 #if defined(_WIN32) || (defined(__APPLE__) && !defined(MACOSX_USE_GLX))
1109   if (!aDisplayName.IsEmpty())
1110   {
1111     aDisplayName.Clear();
1112     std::cout << "Warning: display parameter will be ignored.\n";
1113   }
1114 #endif
1115
1116   ViewerTest_Names aViewNames (aViewName);
1117   if (ViewerTest_myViews.IsBound1 (aViewNames.GetViewName()))
1118   {
1119     TCollection_AsciiString aCommand = TCollection_AsciiString ("vactivate ") + aViewNames.GetViewName();
1120     theDi.Eval (aCommand.ToCString());
1121     if (is2dMode != -1)
1122     {
1123       ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1124     }
1125     return 0;
1126   }
1127
1128   TCollection_AsciiString aViewId = ViewerTest::ViewerInit (aPxLeft, aPxTop, aPxWidth, aPxHeight,
1129                                                             aViewName, aDisplayName, aCopyFrom);
1130   if (is2dMode != -1)
1131   {
1132     ViewerTest_V3dView::SetCurrentView2DMode (is2dMode == 1);
1133   }
1134   theDi << aViewId;
1135   return 0;
1136 }
1137
1138 //! Parse HLR algo type.
1139 static Standard_Boolean parseHlrAlgoType (const char* theName,
1140                                           Prs3d_TypeOfHLR& theType)
1141 {
1142   TCollection_AsciiString aName (theName);
1143   aName.LowerCase();
1144   if (aName == "polyalgo")
1145   {
1146     theType = Prs3d_TOH_PolyAlgo;
1147   }
1148   else if (aName == "algo")
1149   {
1150     theType = Prs3d_TOH_Algo;
1151   }
1152   else
1153   {
1154     return Standard_False;
1155   }
1156   return Standard_True;
1157 }
1158
1159 //==============================================================================
1160 //function : VHLR
1161 //purpose  : hidden lines removal algorithm
1162 //==============================================================================
1163
1164 static int VHLR (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
1165 {
1166   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1167   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1168   if (aView.IsNull())
1169   {
1170     std::cerr << "Error: No opened viewer!\n";
1171     return 1;
1172   }
1173
1174   Standard_Boolean hasHlrOnArg = Standard_False;
1175   Standard_Boolean hasShowHiddenArg = Standard_False;
1176   Standard_Boolean isHLROn = Standard_False;
1177   Standard_Boolean toShowHidden = aCtx->DefaultDrawer()->DrawHiddenLine();
1178   Prs3d_TypeOfHLR  aTypeOfHLR = Prs3d_TOH_NotSet;
1179   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1180   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1181   {
1182     TCollection_AsciiString anArg (argv[anArgIter]);
1183     anArg.LowerCase();
1184     if (anUpdateTool.parseRedrawMode (anArg))
1185     {
1186       continue;
1187     }
1188     else if (anArg == "-showhidden"
1189           && anArgIter + 1 < argc
1190           && ViewerTest::ParseOnOff (argv[anArgIter + 1], toShowHidden))
1191     {
1192       ++anArgIter;
1193       hasShowHiddenArg = Standard_True;
1194       continue;
1195     }
1196     else if ((anArg == "-type"
1197            || anArg == "-algo"
1198            || anArg == "-algotype")
1199           && anArgIter + 1 < argc
1200           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1201     {
1202       ++anArgIter;
1203       continue;
1204     }
1205     else if (!hasHlrOnArg
1206           && ViewerTest::ParseOnOff (argv[anArgIter], isHLROn))
1207     {
1208       hasHlrOnArg = Standard_True;
1209       continue;
1210     }
1211     // old syntax
1212     else if (!hasShowHiddenArg
1213           && ViewerTest::ParseOnOff(argv[anArgIter], toShowHidden))
1214     {
1215       hasShowHiddenArg = Standard_True;
1216       continue;
1217     }
1218     else
1219     {
1220       std::cout << "Syntax error at '" << argv[anArgIter] << "'\n";
1221       return 1;
1222     }
1223   }
1224   if (!hasHlrOnArg)
1225   {
1226     di << "HLR:        " << aView->ComputedMode() << "\n";
1227     di << "HiddenLine: " << aCtx->DefaultDrawer()->DrawHiddenLine() << "\n";
1228     di << "HlrAlgo:    ";
1229     switch (aCtx->DefaultDrawer()->TypeOfHLR())
1230     {
1231       case Prs3d_TOH_NotSet:   di << "NotSet\n";   break;
1232       case Prs3d_TOH_PolyAlgo: di << "PolyAlgo\n"; break;
1233       case Prs3d_TOH_Algo:     di << "Algo\n";     break;
1234     }
1235     anUpdateTool.Invalidate();
1236     return 0;
1237   }
1238
1239   Standard_Boolean toRecompute = Standard_False;
1240   if (aTypeOfHLR != Prs3d_TOH_NotSet
1241    && aTypeOfHLR != aCtx->DefaultDrawer()->TypeOfHLR())
1242   {
1243     toRecompute = Standard_True;
1244     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1245   }
1246   if (toShowHidden != aCtx->DefaultDrawer()->DrawHiddenLine())
1247   {
1248     toRecompute = Standard_True;
1249     if (toShowHidden)
1250     {
1251       aCtx->DefaultDrawer()->EnableDrawHiddenLine();
1252     }
1253     else
1254     {
1255       aCtx->DefaultDrawer()->DisableDrawHiddenLine();
1256     }
1257   }
1258
1259   // redisplay shapes
1260   if (aView->ComputedMode() && isHLROn && toRecompute)
1261   {
1262     AIS_ListOfInteractive aListOfShapes;
1263     aCtx->DisplayedObjects (aListOfShapes);
1264     for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
1265     {
1266       if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value()))
1267       {
1268         aCtx->Redisplay (aShape, Standard_False);
1269       }
1270     }
1271   }
1272
1273   aView->SetComputedMode (isHLROn);
1274   return 0;
1275 }
1276
1277 //==============================================================================
1278 //function : VHLRType
1279 //purpose  : change type of using HLR algorithm
1280 //==============================================================================
1281
1282 static int VHLRType (Draw_Interpretor& , Standard_Integer argc, const char** argv)
1283 {
1284   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1285   const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1286   if (aView.IsNull())
1287   {
1288     std::cerr << "Error: No opened viewer!\n";
1289     return 1;
1290   }
1291
1292   Prs3d_TypeOfHLR aTypeOfHLR = Prs3d_TOH_NotSet;
1293   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
1294   AIS_ListOfInteractive aListOfShapes;
1295   for (Standard_Integer anArgIter = 1; anArgIter < argc; ++anArgIter)
1296   {
1297     TCollection_AsciiString anArg (argv[anArgIter]);
1298     anArg.LowerCase();
1299     if (anUpdateTool.parseRedrawMode (anArg))
1300     {
1301       continue;
1302     }
1303     else if ((anArg == "-type"
1304            || anArg == "-algo"
1305            || anArg == "-algotype")
1306           && anArgIter + 1 < argc
1307           && parseHlrAlgoType (argv[anArgIter + 1], aTypeOfHLR))
1308     {
1309       ++anArgIter;
1310       continue;
1311     }
1312     // old syntax
1313     else if (aTypeOfHLR == Prs3d_TOH_NotSet
1314           && parseHlrAlgoType (argv[anArgIter], aTypeOfHLR))
1315     {
1316       continue;
1317     }
1318     else
1319     {
1320       ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
1321       TCollection_AsciiString aName (argv[anArgIter]);
1322       if (!aMap.IsBound2 (aName))
1323       {
1324         std::cout << "Syntax error: Wrong shape name '" << aName << "'.\n";
1325         return 1;
1326       }
1327
1328       Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aMap.Find2 (aName));
1329       if (aShape.IsNull())
1330       {
1331         std::cout << "Syntax error: '" << aName << "' is not a shape presentation.\n";
1332         return 1;
1333       }
1334       aListOfShapes.Append (aShape);
1335       continue;
1336     }
1337   }
1338   if (aTypeOfHLR == Prs3d_TOH_NotSet)
1339   {
1340     std::cout << "Syntax error: wrong number of arguments!\n";
1341     return 1;
1342   }
1343
1344   const Standard_Boolean isGlobal = aListOfShapes.IsEmpty();
1345   if (isGlobal)
1346   {
1347     aCtx->DisplayedObjects (aListOfShapes);
1348     aCtx->DefaultDrawer()->SetTypeOfHLR (aTypeOfHLR);
1349   }
1350
1351   for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes); anIter.More(); anIter.Next())
1352   {
1353     Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
1354     if (aShape.IsNull())
1355     {
1356       continue;
1357     }
1358
1359     const bool toUpdateShape = aShape->TypeOfHLR() != aTypeOfHLR
1360                             && aView->ComputedMode();
1361     if (!isGlobal
1362      || aShape->TypeOfHLR() != aTypeOfHLR)
1363     {
1364       aShape->SetTypeOfHLR (aTypeOfHLR);
1365     }
1366     if (toUpdateShape)
1367     {
1368       aCtx->Redisplay (aShape, Standard_False);
1369     }
1370   }
1371   return 0;
1372 }
1373
1374 //==============================================================================
1375 //function : FindViewIdByWindowHandle
1376 //purpose  : Find theView Id in the map of views by window handle
1377 //==============================================================================
1378 #if defined(_WIN32) || defined(__WIN32__) || (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1379 TCollection_AsciiString FindViewIdByWindowHandle(const Aspect_Handle theWindowHandle)
1380 {
1381   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator
1382        anIter(ViewerTest_myViews); anIter.More(); anIter.Next())
1383   {
1384     Aspect_Handle aWindowHandle = GetWindowHandle(anIter.Value()->Window());
1385     if (aWindowHandle == theWindowHandle)
1386       return anIter.Key1();
1387   }
1388   return TCollection_AsciiString("");
1389 }
1390 #endif
1391
1392 //! Make the view active
1393 void ActivateView (const TCollection_AsciiString& theViewName,
1394                    Standard_Boolean theToUpdate = Standard_True)
1395 {
1396   const Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1397   if (aView.IsNull())
1398   {
1399     return;
1400   }
1401
1402   Handle(AIS_InteractiveContext) anAISContext = FindContextByView(aView);
1403   if (!anAISContext.IsNull())
1404   {
1405     if (!ViewerTest::CurrentView().IsNull())
1406     {
1407       TCollection_AsciiString aTitle("3D View - ");
1408       aTitle = aTitle + ViewerTest_myViews.Find2 (ViewerTest::CurrentView());
1409       SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
1410     }
1411
1412     ViewerTest::CurrentView (aView);
1413     ViewerTest::SetAISContext (anAISContext);
1414     TCollection_AsciiString aTitle = TCollection_AsciiString("3D View - ") + theViewName + "(*)";
1415     SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
1416 #if defined(_WIN32)
1417     VT_GetWindow() = Handle(WNT_Window)::DownCast(ViewerTest::CurrentView()->Window());
1418 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
1419     VT_GetWindow() = Handle(Cocoa_Window)::DownCast(ViewerTest::CurrentView()->Window());
1420 #else
1421     VT_GetWindow() = Handle(Xw_Window)::DownCast(ViewerTest::CurrentView()->Window());
1422 #endif
1423     SetDisplayConnection(ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
1424     if (theToUpdate)
1425     {
1426       ViewerTest::CurrentView()->Redraw();
1427     }
1428   }
1429 }
1430
1431 //==============================================================================
1432 //function : RemoveView
1433 //purpose  :
1434 //==============================================================================
1435 void ViewerTest::RemoveView (const Handle(V3d_View)& theView,
1436                              const Standard_Boolean  theToRemoveContext)
1437 {
1438   if (!ViewerTest_myViews.IsBound2 (theView))
1439   {
1440     return;
1441   }
1442
1443   const TCollection_AsciiString aViewName = ViewerTest_myViews.Find2 (theView);
1444   RemoveView (aViewName, theToRemoveContext);
1445 }
1446
1447 //==============================================================================
1448 //function : RemoveView
1449 //purpose  : Close and remove view from display, clear maps if neccessary
1450 //==============================================================================
1451 void ViewerTest::RemoveView (const TCollection_AsciiString& theViewName, const Standard_Boolean isContextRemoved)
1452 {
1453   if (!ViewerTest_myViews.IsBound1(theViewName))
1454   {
1455     cout << "Wrong view name\n";
1456     return;
1457   }
1458
1459   // Activate another view if it's active now
1460   if (ViewerTest_myViews.Find1(theViewName) == ViewerTest::CurrentView())
1461   {
1462     if (ViewerTest_myViews.Extent() > 1)
1463     {
1464       TCollection_AsciiString aNewViewName;
1465       for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1466            anIter.More(); anIter.Next())
1467       {
1468         if (anIter.Key1() != theViewName)
1469         {
1470           aNewViewName = anIter.Key1();
1471           break;
1472         }
1473       }
1474       ActivateView (aNewViewName);
1475     }
1476     else
1477     {
1478       VT_GetWindow().Nullify();
1479       ViewerTest::CurrentView (Handle(V3d_View)());
1480       if (isContextRemoved)
1481       {
1482         Handle(AIS_InteractiveContext) anEmptyContext;
1483         ViewerTest::SetAISContext(anEmptyContext);
1484       }
1485     }
1486   }
1487
1488   // Delete view
1489   Handle(V3d_View) aView = ViewerTest_myViews.Find1(theViewName);
1490   Handle(AIS_InteractiveContext) aCurrentContext = FindContextByView(aView);
1491   ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
1492   aRedrawer.Stop (aView->Window());
1493
1494   // Remove view resources
1495   ViewerTest_myViews.UnBind1(theViewName);
1496   aView->Window()->Unmap();
1497   aView->Remove();
1498
1499 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1500   XFlush (GetDisplayConnection()->GetDisplay());
1501 #endif
1502
1503   // Keep context opened only if the closed view is last to avoid
1504   // unused empty contexts
1505   if (!aCurrentContext.IsNull())
1506   {
1507     // Check if there are more difined views in the viewer
1508     aCurrentContext->CurrentViewer()->InitDefinedViews();
1509     if ((isContextRemoved || ViewerTest_myContexts.Size() != 1) && !aCurrentContext->CurrentViewer()->MoreDefinedViews())
1510     {
1511       // Remove driver if there is no viewers that use it
1512       Standard_Boolean isRemoveDriver = Standard_True;
1513       for(NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1514           anIter(ViewerTest_myContexts); anIter.More(); anIter.Next())
1515       {
1516         if (aCurrentContext != anIter.Key2() &&
1517           aCurrentContext->CurrentViewer()->Driver() == anIter.Value()->CurrentViewer()->Driver())
1518         {
1519           isRemoveDriver = Standard_False;
1520           break;
1521         }
1522       }
1523
1524       aCurrentContext->RemoveAll (Standard_False);
1525       if(isRemoveDriver)
1526       {
1527         ViewerTest_myDrivers.UnBind2 (aCurrentContext->CurrentViewer()->Driver());
1528       #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
1529         Tcl_DeleteFileHandler (XConnectionNumber (aCurrentContext->CurrentViewer()->Driver()->GetDisplayConnection()->GetDisplay()));
1530       #endif
1531       }
1532
1533       ViewerTest_myContexts.UnBind2(aCurrentContext);
1534     }
1535   }
1536   cout << "3D View - " << theViewName << " was deleted.\n";
1537   if (Draw_ToExitOnCloseView)
1538   {
1539     Draw_Interprete ("exit");
1540   }
1541 }
1542
1543 //==============================================================================
1544 //function : VClose
1545 //purpose  : Remove the view defined by its name
1546 //==============================================================================
1547
1548 static int VClose (Draw_Interpretor& /*theDi*/,
1549                    Standard_Integer  theArgsNb,
1550                    const char**      theArgVec)
1551 {
1552   NCollection_List<TCollection_AsciiString> aViewList;
1553   if (theArgsNb > 1)
1554   {
1555     TCollection_AsciiString anArg (theArgVec[1]);
1556     anArg.UpperCase();
1557     if (anArg.IsEqual ("ALL")
1558      || anArg.IsEqual ("*"))
1559     {
1560       for (NCollection_DoubleMap<TCollection_AsciiString, Handle(V3d_View)>::Iterator anIter (ViewerTest_myViews);
1561            anIter.More(); anIter.Next())
1562       {
1563         aViewList.Append (anIter.Key1());
1564       }
1565       if (aViewList.IsEmpty())
1566       {
1567         std::cout << "No view to close\n";
1568         return 0;
1569       }
1570     }
1571     else
1572     {
1573       ViewerTest_Names aViewName (theArgVec[1]);
1574       if (!ViewerTest_myViews.IsBound1 (aViewName.GetViewName()))
1575       {
1576         std::cerr << "The view with name '" << theArgVec[1] << "' does not exist\n";
1577         return 1;
1578       }
1579       aViewList.Append (aViewName.GetViewName());
1580     }
1581   }
1582   else
1583   {
1584     // close active view
1585     if (ViewerTest::CurrentView().IsNull())
1586     {
1587       std::cerr << "No active view!\n";
1588       return 1;
1589     }
1590     aViewList.Append (ViewerTest_myViews.Find2 (ViewerTest::CurrentView()));
1591   }
1592
1593   Standard_Boolean toRemoveContext = (theArgsNb != 3 || Draw::Atoi (theArgVec[2]) != 1);
1594   for (NCollection_List<TCollection_AsciiString>::Iterator anIter(aViewList);
1595        anIter.More(); anIter.Next())
1596   {
1597     ViewerTest::RemoveView (anIter.Value(), toRemoveContext);
1598   }
1599
1600   return 0;
1601 }
1602
1603 //==============================================================================
1604 //function : VActivate
1605 //purpose  : Activate the view defined by its ID
1606 //==============================================================================
1607
1608 static int VActivate (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1609 {
1610   if (theArgsNb == 1)
1611   {
1612     theDi.Eval("vviewlist");
1613     return 0;
1614   }
1615
1616   TCollection_AsciiString aNameString;
1617   Standard_Boolean toUpdate = Standard_True;
1618   Standard_Boolean toActivate = Standard_True;
1619   for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
1620   {
1621     TCollection_AsciiString anArg (theArgVec[anArgIter]);
1622     anArg.LowerCase();
1623     if (toUpdate
1624      && anArg == "-noupdate")
1625     {
1626       toUpdate = Standard_False;
1627     }
1628     else if (toActivate
1629           && aNameString.IsEmpty()
1630           && anArg == "none")
1631     {
1632       TCollection_AsciiString aTitle("3D View - ");
1633       aTitle = aTitle + ViewerTest_myViews.Find2(ViewerTest::CurrentView());
1634       SetWindowTitle (ViewerTest::CurrentView()->Window(), aTitle.ToCString());
1635       VT_GetWindow().Nullify();
1636       ViewerTest::CurrentView (Handle(V3d_View)());
1637       ViewerTest::ResetEventManager();
1638       theDi << theArgVec[0] << ": all views are inactive\n";
1639       toActivate = Standard_False;
1640     }
1641     else if (toActivate
1642           && aNameString.IsEmpty())
1643     {
1644       aNameString = theArgVec[anArgIter];
1645     }
1646     else
1647     {
1648       std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
1649       return 1;
1650     }
1651   }
1652
1653   if (!toActivate)
1654   {
1655     return 0;
1656   }
1657   else if (aNameString.IsEmpty())
1658   {
1659     std::cout << "Syntax error: wrong number of arguments\n";
1660     return 1;
1661   }
1662
1663   // Check if this view exists in the viewer with the driver
1664   ViewerTest_Names aViewNames (aNameString);
1665   if (!ViewerTest_myViews.IsBound1(aViewNames.GetViewName()))
1666   {
1667     theDi << "Syntax error: wrong view name '" << aNameString << "'\n";
1668     return 1;
1669   }
1670
1671   // Check if it is active already
1672   if (ViewerTest::CurrentView() == ViewerTest_myViews.Find1(aViewNames.GetViewName()))
1673   {
1674     theDi << theArgVec[0] << ": the view is active already\n";
1675     return 0;
1676   }
1677
1678   ActivateView (aViewNames.GetViewName(), toUpdate);
1679   return 0;
1680 }
1681
1682 //==============================================================================
1683 //function : VViewList
1684 //purpose  : Print current list of views per viewer and graphic driver ID
1685 //           shared between viewers
1686 //==============================================================================
1687
1688 static int VViewList (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
1689 {
1690   if (theArgsNb > 2)
1691   {
1692     theDi << theArgVec[0] << ": Wrong number of command arguments\n"
1693           << "Usage: " << theArgVec[0] << " name";
1694     return 1;
1695   }
1696   if (ViewerTest_myContexts.Size() < 1)
1697     return 0;
1698
1699   Standard_Boolean isTreeView =
1700     (( theArgsNb==1 ) || ( strcasecmp( theArgVec[1], "long" ) != 0 ));
1701
1702   if (isTreeView)
1703   {
1704     theDi << theArgVec[0] <<":\n";
1705   }
1706
1707   for (NCollection_DoubleMap <TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator aDriverIter (ViewerTest_myDrivers);
1708        aDriverIter.More(); aDriverIter.Next())
1709   {
1710     if (isTreeView)
1711       theDi << aDriverIter.Key1() << ":\n";
1712
1713     for (NCollection_DoubleMap <TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
1714       aContextIter(ViewerTest_myContexts); aContextIter.More(); aContextIter.Next())
1715     {
1716       if (aContextIter.Key1().Search(aDriverIter.Key1()) != -1)
1717       {
1718         if (isTreeView)
1719         {
1720           TCollection_AsciiString aContextName(aContextIter.Key1());
1721           theDi << " " << aContextName.Split(aDriverIter.Key1().Length() + 1) << ":\n";
1722         }
1723
1724         for (NCollection_DoubleMap <TCollection_AsciiString, Handle(V3d_View)>::Iterator aViewIter (ViewerTest_myViews);
1725              aViewIter.More(); aViewIter.Next())
1726         {
1727           if (aViewIter.Key1().Search(aContextIter.Key1()) != -1)
1728           {
1729             TCollection_AsciiString aViewName(aViewIter.Key1());
1730             if (isTreeView)
1731             {
1732               if (aViewIter.Value() == ViewerTest::CurrentView())
1733                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "(*)\n";
1734               else
1735                 theDi << "  " << aViewName.Split(aContextIter.Key1().Length() + 1) << "\n";
1736             }
1737             else
1738             {
1739               theDi << aViewName << " ";
1740             }
1741           }
1742         }
1743       }
1744     }
1745   }
1746   return 0;
1747 }
1748
1749 //==============================================================================
1750 //function : VT_ProcessKeyPress
1751 //purpose  : Handle KeyPress event from a CString
1752 //==============================================================================
1753 void VT_ProcessKeyPress (const char* buf_ret)
1754 {
1755   //cout << "KeyPress" << endl;
1756   const Handle(V3d_View) aView = ViewerTest::CurrentView();
1757   // Letter in alphabetic order
1758
1759   if (!strcasecmp (buf_ret, "A")
1760    && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
1761   {
1762     // AXO
1763     aView->SetProj(V3d_XposYnegZpos);
1764   }
1765   else if (!strcasecmp (buf_ret, "D")
1766         && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
1767   {
1768     // Reset
1769     aView->Reset();
1770   }
1771   else if (!strcasecmp (buf_ret, "F"))
1772   {
1773     if (ViewerTest::GetAISContext()->NbSelected() > 0)
1774     {
1775       ViewerTest::GetAISContext()->FitSelected (aView);
1776     }
1777     else
1778     {
1779       // FitAll
1780       aView->FitAll();
1781     }
1782   }
1783   else if (!strcasecmp (buf_ret, "H"))
1784   {
1785     // HLR
1786     std::cout << "HLR" << std::endl;
1787     aView->SetComputedMode (!aView->ComputedMode());
1788     aView->Redraw();
1789   }
1790   else if (!strcasecmp (buf_ret, "P"))
1791   {
1792     // Type of HLR
1793     Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
1794     if (aContext->DefaultDrawer()->TypeOfHLR() == Prs3d_TOH_Algo)
1795       aContext->DefaultDrawer()->SetTypeOfHLR(Prs3d_TOH_PolyAlgo);
1796     else
1797       aContext->DefaultDrawer()->SetTypeOfHLR(Prs3d_TOH_Algo);
1798     if (aContext->NbSelected()==0)
1799     {
1800       AIS_ListOfInteractive aListOfShapes;
1801       aContext->DisplayedObjects(aListOfShapes);
1802       for (AIS_ListIteratorOfListOfInteractive anIter(aListOfShapes);
1803         anIter.More(); anIter.Next())
1804       {
1805         Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(anIter.Value());
1806         if (aShape.IsNull())
1807           continue;
1808         if (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo)
1809           aShape->SetTypeOfHLR (Prs3d_TOH_Algo);
1810         else
1811           aShape->SetTypeOfHLR (Prs3d_TOH_PolyAlgo);
1812         aContext->Redisplay (aShape, Standard_False);
1813       }
1814     }
1815     else
1816     {
1817       for (aContext->InitSelected();aContext->MoreSelected();aContext->NextSelected())
1818       {
1819         Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(aContext->SelectedInteractive());
1820         if (aShape.IsNull())
1821           continue;
1822         if(aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo)
1823           aShape->SetTypeOfHLR (Prs3d_TOH_Algo);
1824         else
1825           aShape->SetTypeOfHLR (Prs3d_TOH_PolyAlgo);
1826         aContext->Redisplay (aShape, Standard_False);
1827       }
1828     }
1829
1830     aContext->UpdateCurrentViewer();
1831
1832   }
1833   else if (!strcasecmp (buf_ret, "S"))
1834   {
1835     std::cout << "setup Shaded display mode" << std::endl;
1836
1837     Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext();
1838     if(Ctx->NbSelected()==0)
1839       Ctx->SetDisplayMode (AIS_Shaded, Standard_True);
1840     else{
1841       for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected())
1842         Ctx->SetDisplayMode(Ctx->SelectedInteractive(),1,Standard_False);
1843       Ctx->UpdateCurrentViewer();
1844     }
1845   }
1846   else if (!strcasecmp (buf_ret, "U"))
1847   {
1848     // Unset display mode
1849     std::cout << "reset display mode to defaults" << std::endl;
1850
1851     Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext();
1852     if(Ctx->NbSelected()==0)
1853       Ctx->SetDisplayMode (AIS_WireFrame, Standard_True);
1854     else{
1855       for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected())
1856         Ctx->UnsetDisplayMode(Ctx->SelectedInteractive(),Standard_False);
1857       Ctx->UpdateCurrentViewer();
1858     }
1859
1860   }
1861   else if (!strcasecmp (buf_ret, "T")
1862         && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
1863   {
1864     // Top
1865     aView->SetProj(V3d_Zpos);
1866   }
1867   else if (!strcasecmp (buf_ret, "B")
1868         && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
1869   {
1870     // Bottom
1871     aView->SetProj(V3d_Zneg);
1872   }
1873   else if (!strcasecmp (buf_ret, "L")
1874         && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
1875   {
1876     // Left
1877     aView->SetProj(V3d_Xneg);
1878   }
1879   else if (!strcasecmp (buf_ret, "R")
1880         && !ViewerTest_V3dView::IsCurrentViewIn2DMode())
1881   {
1882     // Right
1883     aView->SetProj(V3d_Xpos);
1884   }
1885   else if (!strcasecmp (buf_ret, "W"))
1886   {
1887     std::cout << "setup WireFrame display mode" << std::endl;
1888     Handle(AIS_InteractiveContext) Ctx = ViewerTest::GetAISContext();
1889     if(Ctx->NbSelected()==0)
1890       Ctx->SetDisplayMode (AIS_WireFrame, Standard_True);
1891     else{
1892       for(Ctx->InitSelected();Ctx->MoreSelected();Ctx->NextSelected())
1893         Ctx->SetDisplayMode(Ctx->SelectedInteractive(),0,Standard_False);
1894       Ctx->UpdateCurrentViewer();
1895     }
1896   }
1897   else if (!strcasecmp (buf_ret, ","))
1898   {
1899     ViewerTest::GetAISContext()->HilightNextDetected(ViewerTest::CurrentView());
1900   }
1901   else if (!strcasecmp (buf_ret, "."))
1902   {
1903     ViewerTest::GetAISContext()->HilightPreviousDetected(ViewerTest::CurrentView());
1904   }
1905   else if (!strcasecmp (buf_ret, "/"))
1906   {
1907     Handle(Graphic3d_Camera) aCamera = aView->Camera();
1908     if (aCamera->IsStereo())
1909     {
1910       aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01);
1911       aView->Redraw();
1912     }
1913   }
1914   else if (!strcasecmp (buf_ret, "*"))
1915   {
1916     Handle(Graphic3d_Camera) aCamera = aView->Camera();
1917     if (aCamera->IsStereo())
1918     {
1919       aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01);
1920       aView->Redraw();
1921     }
1922   }
1923   else if (*buf_ret == THE_KEY_DELETE)
1924   {
1925     Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1926     if (!aCtx.IsNull()
1927      && aCtx->NbSelected() > 0)
1928     {
1929       Draw_Interprete ("verase");
1930     }
1931   }
1932   else if (*buf_ret == THE_KEY_ESCAPE)
1933   {
1934     Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
1935     if (!aCtx.IsNull()
1936      && Draw_ToCloseViewOnEsc)
1937     {
1938       Draw_Interprete (Draw_ToExitOnCloseView ? "exit" : "vclose");
1939     }
1940   }
1941   else
1942   {
1943     // Number
1944     const Standard_Integer aSelMode = Draw::Atoi(buf_ret);
1945     if (aSelMode >= 0 && aSelMode <= 7)
1946     {
1947       bool toEnable = true;
1948       if (const Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext())
1949       {
1950         AIS_ListOfInteractive aPrsList;
1951         aCtx->DisplayedObjects (aPrsList);
1952         for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More() && toEnable; aPrsIter.Next())
1953         {
1954           TColStd_ListOfInteger aModes;
1955           aCtx->ActivatedModes (aPrsIter.Value(), aModes);
1956           for (TColStd_ListOfInteger::Iterator aModeIter (aModes); aModeIter.More() && toEnable; aModeIter.Next())
1957           {
1958             if (aModeIter.Value() == aSelMode)
1959             {
1960               toEnable = false;
1961             }
1962           }
1963         }
1964       }
1965       TCollection_AsciiString aCmd = TCollection_AsciiString ("vselmode ") + aSelMode + (toEnable ? " 1" : " 0");
1966       Draw_Interprete (aCmd.ToCString());
1967     }
1968   }
1969 }
1970
1971 //==============================================================================
1972 //function : VT_ProcessExpose
1973 //purpose  : Redraw the View on an Expose Event
1974 //==============================================================================
1975 void VT_ProcessExpose()
1976 {
1977   Handle(V3d_View) aView3d = ViewerTest::CurrentView();
1978   if (!aView3d.IsNull())
1979   {
1980     aView3d->Redraw();
1981   }
1982 }
1983
1984 //==============================================================================
1985 //function : VT_ProcessConfigure
1986 //purpose  : Resize the View on an Configure Event
1987 //==============================================================================
1988 void VT_ProcessConfigure()
1989 {
1990   Handle(V3d_View) aView3d = ViewerTest::CurrentView();
1991   if (aView3d.IsNull())
1992   {
1993     return;
1994   }
1995
1996   aView3d->MustBeResized();
1997   aView3d->Update();
1998   aView3d->Redraw();
1999 }
2000
2001 //==============================================================================
2002 //function : VT_ProcessButton1Press
2003 //purpose  : Picking
2004 //==============================================================================
2005 Standard_Boolean VT_ProcessButton1Press (Standard_Integer ,
2006                                          const char**     theArgVec,
2007                                          Standard_Boolean theToPick,
2008                                          Standard_Boolean theIsShift)
2009 {
2010   if (TheIsAnimating)
2011   {
2012     TheIsAnimating = Standard_False;
2013     return Standard_False;
2014   }
2015
2016   if (theToPick)
2017   {
2018     Standard_Real X, Y, Z;
2019     ViewerTest::CurrentView()->Convert (X_Motion, Y_Motion, X, Y, Z);
2020
2021     Draw::Set (theArgVec[1], X);
2022     Draw::Set (theArgVec[2], Y);
2023     Draw::Set (theArgVec[3], Z);
2024   }
2025
2026   if (theIsShift)
2027   {
2028     ViewerTest::CurrentEventManager()->ShiftSelect();
2029   }
2030   else
2031   {
2032     ViewerTest::CurrentEventManager()->Select();
2033   }
2034
2035   return Standard_False;
2036 }
2037
2038 //==============================================================================
2039 //function : VT_ProcessButton1Release
2040 //purpose  : End selecting
2041 //==============================================================================
2042 void VT_ProcessButton1Release (Standard_Boolean theIsShift)
2043 {
2044   if (IsDragged)
2045   {
2046     IsDragged = Standard_False;
2047     Handle(ViewerTest_EventManager) EM = ViewerTest::CurrentEventManager();
2048     if (theIsShift)
2049     {
2050       EM->ShiftSelect (X_ButtonPress, Y_ButtonPress,
2051                        X_Motion, Y_Motion);
2052     }
2053     else
2054     {
2055       EM->Select (X_ButtonPress, Y_ButtonPress,
2056                   X_Motion, Y_Motion);
2057     }
2058   }
2059 }
2060
2061 //==============================================================================
2062 //function : VT_ProcessButton3Press
2063 //purpose  : Start Rotation
2064 //==============================================================================
2065 void VT_ProcessButton3Press()
2066 {
2067   if (ViewerTest_V3dView::IsCurrentViewIn2DMode())
2068   {
2069     return;
2070   }
2071
2072   Start_Rot = 1;
2073   HasHlrOnBeforeRotation = ViewerTest::CurrentView()->ComputedMode();
2074   if (HasHlrOnBeforeRotation)
2075   {
2076     ViewerTest::CurrentView()->SetComputedMode (Standard_False);
2077   }
2078   ViewerTest::CurrentView()->StartRotation( X_ButtonPress, Y_ButtonPress );
2079 }
2080
2081 //==============================================================================
2082 //function : VT_ProcessButton3Release
2083 //purpose  : End rotation
2084 //==============================================================================
2085 void VT_ProcessButton3Release()
2086 {
2087   if (Start_Rot)
2088   {
2089     Start_Rot = 0;
2090     if (HasHlrOnBeforeRotation)
2091     {
2092       HasHlrOnBeforeRotation = Standard_False;
2093       ViewerTest::CurrentView()->SetComputedMode (Standard_True);
2094       ViewerTest::CurrentView()->Redraw();
2095     }
2096   }
2097 }
2098
2099 //==============================================================================
2100 //function : ProcessControlButton1Motion
2101 //purpose  : Zoom
2102 //==============================================================================
2103
2104 #if defined(_WIN32) || ! defined(__APPLE__) || defined(MACOSX_USE_GLX)
2105 static void ProcessControlButton1Motion()
2106 {
2107   ViewerTest::CurrentView()->Zoom( X_ButtonPress, Y_ButtonPress, X_Motion, Y_Motion);
2108
2109   X_ButtonPress = X_Motion;
2110   Y_ButtonPress = Y_Motion;
2111 }
2112 #endif
2113
2114 //==============================================================================
2115 //function : VT_ProcessControlButton2Motion
2116 //purpose  : Panning
2117 //==============================================================================
2118 void VT_ProcessControlButton2Motion()
2119 {
2120   Standard_Integer aDx = X_Motion - X_ButtonPress;
2121   Standard_Integer aDy = Y_Motion - Y_ButtonPress;
2122
2123   aDy = -aDy; // Xwindow Y axis is from top to Bottom
2124
2125   ViewerTest::CurrentView()->Pan (aDx, aDy);
2126
2127   X_ButtonPress = X_Motion;
2128   Y_ButtonPress = Y_Motion;
2129 }
2130
2131 //==============================================================================
2132 //function : VT_ProcessControlButton3Motion
2133 //purpose  : Rotation
2134 //==============================================================================
2135 void VT_ProcessControlButton3Motion()
2136 {
2137   if (Start_Rot)
2138   {
2139     ViewerTest::CurrentView()->Rotation (X_Motion, Y_Motion);
2140   }
2141 }
2142
2143 //==============================================================================
2144 //function : VT_ProcessMotion
2145 //purpose  :
2146 //==============================================================================
2147 void VT_ProcessMotion()
2148 {
2149   //pre-hilights detected objects at mouse position
2150
2151   Handle(ViewerTest_EventManager) EM = ViewerTest::CurrentEventManager();
2152   EM->MoveTo(X_Motion, Y_Motion);
2153 }
2154
2155
2156 void ViewerTest::GetMousePosition(Standard_Integer& Xpix,Standard_Integer& Ypix)
2157 {
2158   Xpix = X_Motion;Ypix=Y_Motion;
2159 }
2160
2161 //==============================================================================
2162 //function : ViewProject: implements VAxo, VTop, VLeft, ...
2163 //purpose  : Switches to an axonometric, top, left and other views
2164 //==============================================================================
2165
2166 static int ViewProject(Draw_Interpretor& di, const V3d_TypeOfOrientation ori)
2167 {
2168   if ( ViewerTest::CurrentView().IsNull() )
2169   {
2170     di<<"Call vinit before this command, please\n";
2171     return 1;
2172   }
2173
2174   ViewerTest::CurrentView()->SetProj(ori);
2175   return 0;
2176 }
2177
2178 //==============================================================================
2179 //function : VAxo
2180 //purpose  : Switch to an Axonometric view
2181 //Draw arg : No args
2182 //==============================================================================
2183
2184 static int VAxo(Draw_Interpretor& di, Standard_Integer , const char** )
2185 {
2186   return ViewProject(di, V3d_XposYnegZpos);
2187 }
2188
2189 //==============================================================================
2190 //function : VTop
2191 //purpose  : Switch to a Top View
2192 //Draw arg : No args
2193 //==============================================================================
2194
2195 static int VTop(Draw_Interpretor& di, Standard_Integer , const char** )
2196 {
2197   return ViewProject(di, V3d_Zpos);
2198 }
2199
2200 //==============================================================================
2201 //function : VBottom
2202 //purpose  : Switch to a Bottom View
2203 //Draw arg : No args
2204 //==============================================================================
2205
2206 static int VBottom(Draw_Interpretor& di, Standard_Integer , const char** )
2207 {
2208   return ViewProject(di, V3d_Zneg);
2209 }
2210
2211 //==============================================================================
2212 //function : VLeft
2213 //purpose  : Switch to a Left View
2214 //Draw arg : No args
2215 //==============================================================================
2216
2217 static int VLeft(Draw_Interpretor& di, Standard_Integer , const char** )
2218 {
2219   return ViewProject(di, V3d_Xneg);
2220 }
2221
2222 //==============================================================================
2223 //function : VRight
2224 //purpose  : Switch to a Right View
2225 //Draw arg : No args
2226 //==============================================================================
2227
2228 static int VRight(Draw_Interpretor& di, Standard_Integer , const char** )
2229 {
2230   return ViewProject(di, V3d_Xpos);
2231 }
2232
2233 //==============================================================================
2234 //function : VFront
2235 //purpose  : Switch to a Front View
2236 //Draw arg : No args
2237 //==============================================================================
2238
2239 static int VFront(Draw_Interpretor& di, Standard_Integer , const char** )
2240 {
2241   return ViewProject(di, V3d_Yneg);
2242 }
2243
2244 //==============================================================================
2245 //function : VBack
2246 //purpose  : Switch to a Back View
2247 //Draw arg : No args
2248 //==============================================================================
2249
2250 static int VBack(Draw_Interpretor& di, Standard_Integer , const char** )
2251 {
2252   return ViewProject(di, V3d_Ypos);
2253 }
2254
2255 //==============================================================================
2256 //function : VHelp
2257 //purpose  : Dsiplay help on viewer Keyboead and mouse commands
2258 //Draw arg : No args
2259 //==============================================================================
2260
2261 static int VHelp(Draw_Interpretor& di, Standard_Integer , const char** )
2262 {
2263
2264   di << "Q : Quit the application\n";
2265
2266   di << "=========================\n";
2267   di << "F : FitAll\n";
2268   di << "T : TopView\n";
2269   di << "B : BottomView\n";
2270   di << "R : RightView\n";
2271   di << "L : LeftView\n";
2272   di << "A : AxonometricView\n";
2273   di << "D : ResetView\n";
2274
2275   di << "=========================\n";
2276   di << "S : Shading\n";
2277   di << "W : Wireframe\n";
2278   di << "H : HidelLineRemoval\n";
2279   di << "U : Unset display mode\n";
2280   di << "Delete : Remove selection from viewer\n";
2281
2282   di << "=========================\n";
2283   di << "Selection mode \n";
2284   di << "0 : Shape\n";
2285   di << "1 : Vertex\n";
2286   di << "2 : Edge\n";
2287   di << "3 : Wire\n";
2288   di << "4 : Face\n";
2289   di << "5 : Shell\n";
2290   di << "6 : Solid\n";
2291   di << "7 : Compound\n";
2292
2293   di << "=========================\n";
2294   di << "Z : Switch Z clipping On/Off\n";
2295   di << ", : Hilight next detected\n";
2296   di << ". : Hilight previous detected\n";
2297
2298   return 0;
2299 }
2300
2301 #ifdef _WIN32
2302
2303 static Standard_Boolean Ppick = 0;
2304 static Standard_Integer Pargc = 0;
2305 static const char**           Pargv = NULL;
2306
2307
2308 static LRESULT WINAPI AdvViewerWindowProc( HWND hwnd,
2309                                           UINT Msg,
2310                                           WPARAM wParam,
2311                                           LPARAM lParam )
2312 {
2313   if (!ViewerTest_myViews.IsEmpty()) {
2314
2315     WPARAM fwKeys = wParam;
2316
2317     switch( Msg ) {
2318     case WM_CLOSE:
2319        {
2320          // Delete view from map of views
2321          ViewerTest::RemoveView(FindViewIdByWindowHandle(hwnd));
2322          return 0;
2323        }
2324        break;
2325     case WM_ACTIVATE:
2326       if(LOWORD(wParam) == WA_CLICKACTIVE || LOWORD(wParam) == WA_ACTIVE
2327         || ViewerTest::CurrentView().IsNull())
2328       {
2329         // Activate inactive window
2330         if(GetWindowHandle(VT_GetWindow()) != hwnd)
2331         {
2332           ActivateView (FindViewIdByWindowHandle(hwnd));
2333         }
2334       }
2335       break;
2336
2337     case WM_LBUTTONUP:
2338       if (IsDragged && !DragFirst)
2339       {
2340         if (!GetActiveAISManipulator().IsNull())
2341         {
2342           GetActiveAISManipulator()->StopTransform();
2343           ViewerTest::GetAISContext()->ClearSelected (Standard_True);
2344         }
2345
2346         if (ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand()))
2347         {
2348           ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False);
2349           ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate();
2350         }
2351
2352         VT_ProcessButton1Release ((fwKeys & MK_SHIFT) != 0);
2353       }
2354       IsDragged = Standard_False;
2355       return ViewerWindowProc( hwnd, Msg, wParam, lParam );
2356
2357     case WM_RBUTTONUP:
2358       if (IsDragged && !DragFirst)
2359       {
2360         if (!GetActiveAISManipulator().IsNull())
2361         {
2362           GetActiveAISManipulator()->StopTransform (Standard_False);
2363           ViewerTest::GetAISContext()->ClearSelected (Standard_True);
2364         }
2365         IsDragged = Standard_False;
2366       }
2367       return ViewerWindowProc (hwnd, Msg, wParam, lParam);
2368
2369     case WM_LBUTTONDOWN:
2370       if (!GetActiveAISManipulator().IsNull())
2371       {
2372         IsDragged = ( fwKeys == MK_LBUTTON );
2373       }
2374       else
2375       {
2376         IsDragged = ( fwKeys == MK_LBUTTON || fwKeys == ( MK_LBUTTON | MK_SHIFT ) );
2377       }
2378
2379       if (IsDragged)
2380       {
2381         DragFirst = Standard_True;
2382         X_ButtonPress = LOWORD(lParam);
2383         Y_ButtonPress = HIWORD(lParam);
2384       }
2385       return ViewerWindowProc( hwnd, Msg, wParam, lParam );
2386
2387     case WM_MOUSEMOVE:
2388       if (IsDragged)
2389       {
2390         X_Motion = LOWORD (lParam);
2391         Y_Motion = HIWORD (lParam);
2392         if (!GetActiveAISManipulator().IsNull())
2393         {
2394           if (DragFirst)
2395           {
2396             GetActiveAISManipulator()->StartTransform (X_ButtonPress, Y_ButtonPress, ViewerTest::CurrentView());
2397           }
2398           else
2399           {
2400             GetActiveAISManipulator()->Transform (X_Motion, Y_Motion, ViewerTest::CurrentView());
2401             ViewerTest::GetAISContext()->CurrentViewer()->Redraw();
2402           }
2403         }
2404         else
2405         {
2406           bool toRedraw = false;
2407           if (!DragFirst && ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand()))
2408           {
2409             ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False);
2410             toRedraw = true;
2411           }
2412
2413           RECT aRect;
2414           if (GetClientRect (hwnd, &aRect))
2415           {
2416             int aHeight = aRect.bottom - aRect.top;
2417             GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion);
2418             ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, AIS_DS_Displayed);
2419             toRedraw = true;
2420           }
2421           if (toRedraw)
2422           {
2423             ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate();
2424           }
2425         }
2426
2427         DragFirst = Standard_False;
2428       }
2429       else
2430         return ViewerWindowProc( hwnd, Msg, wParam, lParam );
2431       break;
2432
2433     default:
2434       return ViewerWindowProc( hwnd, Msg, wParam, lParam );
2435     }
2436     return 0;
2437   }
2438   return ViewerWindowProc( hwnd, Msg, wParam, lParam );
2439 }
2440
2441
2442 static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
2443                                        UINT Msg,
2444                                        WPARAM wParam,
2445                                        LPARAM lParam )
2446 {
2447   static int Up = 1;
2448   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
2449   if (aView.IsNull())
2450   {
2451     return DefWindowProcW (hwnd, Msg, wParam, lParam);
2452   }
2453
2454     PAINTSTRUCT    ps;
2455
2456     switch( Msg ) {
2457     case WM_PAINT:
2458       BeginPaint(hwnd, &ps);
2459       EndPaint(hwnd, &ps);
2460       VT_ProcessExpose();
2461       break;
2462
2463     case WM_SIZE:
2464       VT_ProcessConfigure();
2465       break;
2466     case WM_MOVE:
2467     case WM_MOVING:
2468     case WM_SIZING:
2469       switch (aView->RenderingParams().StereoMode)
2470       {
2471         case Graphic3d_StereoMode_RowInterlaced:
2472         case Graphic3d_StereoMode_ColumnInterlaced:
2473         case Graphic3d_StereoMode_ChessBoard:
2474           VT_ProcessConfigure(); // track window moves to reverse stereo pair
2475           break;
2476         default:
2477           break;
2478       }
2479       break;
2480
2481     case WM_KEYDOWN:
2482       if ((wParam != VK_SHIFT) && (wParam != VK_CONTROL))
2483       {
2484         char c[2];
2485         c[0] = (char) wParam;
2486         c[1] = '\0';
2487         if (wParam == VK_DELETE)
2488         {
2489           c[0] = THE_KEY_DELETE;
2490         }
2491         else if (wParam == VK_ESCAPE)
2492         {
2493           c[0] = THE_KEY_ESCAPE;
2494         }
2495         // comma
2496         else if (wParam == VK_OEM_COMMA)
2497         {
2498           c[0] = ',';
2499         }
2500         // dot
2501         else if (wParam == VK_OEM_PERIOD)
2502         {
2503           c[0] = '.';
2504         }
2505         else if (wParam == VK_DIVIDE)
2506         {
2507           c[0] = '/';
2508         }
2509         // dot
2510         else if (wParam == VK_MULTIPLY)
2511         {
2512           c[0] = '*';
2513         }
2514         VT_ProcessKeyPress (c);
2515       }
2516       break;
2517
2518     case WM_LBUTTONUP:
2519     case WM_MBUTTONUP:
2520     case WM_RBUTTONUP:
2521       Up = 1;
2522       VT_ProcessButton3Release();
2523       break;
2524
2525     case WM_LBUTTONDOWN:
2526     case WM_MBUTTONDOWN:
2527     case WM_RBUTTONDOWN:
2528       {
2529         WPARAM fwKeys = wParam;
2530
2531         Up = 0;
2532
2533         X_ButtonPress = LOWORD(lParam);
2534         Y_ButtonPress = HIWORD(lParam);
2535
2536         if (Msg == WM_LBUTTONDOWN)
2537         {
2538           if ((fwKeys & MK_CONTROL) != 0)
2539           {
2540             Ppick = VT_ProcessButton1Press (Pargc, Pargv, Ppick, (fwKeys & MK_SHIFT) != 0);
2541           }
2542           else
2543           {
2544             VT_ProcessButton1Press (Pargc, Pargv, Ppick, (fwKeys & MK_SHIFT) != 0);
2545           }
2546         }
2547         else if (Msg == WM_RBUTTONDOWN)
2548         {
2549           // Start rotation
2550           VT_ProcessButton3Press();
2551         }
2552       }
2553       break;
2554
2555     case WM_MOUSEWHEEL:
2556     {
2557       int aDelta = GET_WHEEL_DELTA_WPARAM (wParam);
2558       if (wParam & MK_CONTROL)
2559       {
2560         if (aView->Camera()->IsStereo())
2561         {
2562           Standard_Real aFocus = aView->Camera()->ZFocus() + (aDelta > 0 ? 0.05 : -0.05);
2563           if (aFocus > 0.2
2564            && aFocus < 2.0)
2565           {
2566             aView->Camera()->SetZFocus (aView->Camera()->ZFocusType(), aFocus);
2567             aView->Redraw();
2568           }
2569         }
2570       }
2571       else
2572       {
2573         aView->Zoom (0, 0, aDelta / 40, aDelta / 40);
2574       }
2575       break;
2576     }
2577
2578     case WM_MOUSEMOVE:
2579       {
2580         //cout << "\t WM_MOUSEMOVE" << endl;
2581         WPARAM fwKeys = wParam;
2582         X_Motion = LOWORD(lParam);
2583         Y_Motion = HIWORD(lParam);
2584
2585         if ( Up &&
2586           (fwKeys & ( MK_LBUTTON|MK_MBUTTON|MK_RBUTTON )) != 0 )
2587           {
2588             Up = 0;
2589             X_ButtonPress = LOWORD(lParam);
2590             Y_ButtonPress = HIWORD(lParam);
2591
2592             if ((fwKeys & MK_RBUTTON) != 0) {
2593               // Start rotation
2594               VT_ProcessButton3Press();
2595             }
2596           }
2597
2598           if ((fwKeys & MK_CONTROL) != 0)
2599           {
2600             if ((fwKeys & MK_LBUTTON) != 0)
2601             {
2602               ProcessControlButton1Motion();
2603             }
2604             else if ((fwKeys & MK_MBUTTON) != 0
2605                  || ((fwKeys & MK_LBUTTON) != 0
2606                   && (fwKeys & MK_RBUTTON) != 0))
2607             {
2608               VT_ProcessControlButton2Motion();
2609             }
2610             else if ((fwKeys & MK_RBUTTON) != 0)
2611             {
2612               VT_ProcessControlButton3Motion();
2613             }
2614           }
2615           else if (GetWindowHandle (VT_GetWindow()) == hwnd)
2616           {
2617             VT_ProcessMotion();
2618           }
2619       }
2620       break;
2621
2622     default:
2623       return DefWindowProcW (hwnd, Msg, wParam, lParam);
2624     }
2625     return 0L;
2626 }
2627
2628 //==============================================================================
2629 //function : ViewerMainLoop
2630 //purpose  : Get a Event on the view and dispatch it
2631 //==============================================================================
2632
2633
2634 int ViewerMainLoop(Standard_Integer argc, const char** argv)
2635 {
2636   Ppick = (argc > 0)? 1 : 0;
2637   Pargc = argc;
2638   Pargv = argv;
2639
2640   if ( Ppick ) {
2641     MSG msg;
2642     msg.wParam = 1;
2643
2644     cout << "Start picking" << endl;
2645
2646     while ( Ppick == 1 ) {
2647       // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
2648       if (GetMessageW (&msg, NULL, 0, 0))
2649       {
2650         TranslateMessage (&msg);
2651         DispatchMessageW (&msg);
2652       }
2653     }
2654
2655     cout << "Picking done" << endl;
2656   }
2657
2658   return Ppick;
2659 }
2660
2661 #elif !defined(__APPLE__) || defined(MACOSX_USE_GLX)
2662
2663 int min( int a, int b )
2664 {
2665   if( a<b )
2666     return a;
2667   else
2668     return b;
2669 }
2670
2671 int max( int a, int b )
2672 {
2673   if( a>b )
2674     return a;
2675   else
2676     return b;
2677 }
2678
2679 int ViewerMainLoop (Standard_Integer argc, const char** argv)
2680 {
2681   static XEvent aReport;
2682   const Standard_Boolean toPick = argc > 0;
2683   Standard_Boolean toPickMore = toPick;
2684   Display* aDisplay = GetDisplayConnection()->GetDisplay();
2685   XNextEvent (aDisplay, &aReport);
2686
2687   // Handle event for the chosen display connection
2688   switch (aReport.type)
2689   {
2690     case ClientMessage:
2691     {
2692       if ((Atom)aReport.xclient.data.l[0] == GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW))
2693       {
2694         // Close the window
2695         ViewerTest::RemoveView(FindViewIdByWindowHandle (aReport.xclient.window));
2696         return toPick ? 0 : 1;
2697       }
2698       break;
2699     }
2700     case FocusIn:
2701     {
2702       // Activate inactive view
2703       Window aWindow = GetWindowHandle(VT_GetWindow());
2704       if (aWindow != aReport.xfocus.window)
2705       {
2706         ActivateView (FindViewIdByWindowHandle (aReport.xfocus.window));
2707       }
2708       break;
2709     }
2710     case Expose:
2711     {
2712       Window anXWindow = GetWindowHandle (VT_GetWindow());
2713       if (anXWindow == aReport.xexpose.window)
2714       {
2715         VT_ProcessExpose();
2716       }
2717
2718       // remove all the ExposureMask and process them at once
2719       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
2720       {
2721         if (!XCheckWindowEvent (aDisplay, anXWindow, ExposureMask, &aReport))
2722         {
2723           break;
2724         }
2725       }
2726
2727       break;
2728     }
2729     case ConfigureNotify:
2730     {
2731       // remove all the StructureNotifyMask and process them at once
2732       Window anXWindow = GetWindowHandle (VT_GetWindow());
2733       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
2734       {
2735         if (!XCheckWindowEvent (aDisplay, anXWindow, StructureNotifyMask, &aReport))
2736         {
2737           break;
2738         }
2739       }
2740
2741       if (anXWindow == aReport.xconfigure.window)
2742       {
2743         VT_ProcessConfigure();
2744       }
2745       break;
2746     }
2747     case KeyPress:
2748     {
2749       KeySym aKeySym;
2750       char aKeyBuf[11];
2751       XComposeStatus status_in_out;
2752       int aKeyLen = XLookupString ((XKeyEvent* )&aReport, (char* )aKeyBuf, 10, &aKeySym, &status_in_out);
2753       aKeyBuf[aKeyLen] = '\0';
2754       if (aKeyLen != 0)
2755       {
2756         VT_ProcessKeyPress (aKeyBuf);
2757       }
2758       break;
2759     }
2760     case ButtonPress:
2761     {
2762       X_ButtonPress = aReport.xbutton.x;
2763       Y_ButtonPress = aReport.xbutton.y;
2764       if (aReport.xbutton.button == Button1)
2765       {
2766         if (aReport.xbutton.state & ControlMask)
2767         {
2768           toPickMore = VT_ProcessButton1Press (argc, argv, toPick, (aReport.xbutton.state & ShiftMask) != 0);
2769         }
2770         else
2771         {
2772           IsDragged = Standard_True;
2773           DragFirst = Standard_True;
2774         }
2775       }
2776       else if (aReport.xbutton.button == Button3)
2777       {
2778         // Start rotation
2779         VT_ProcessButton3Press();
2780       }
2781       break;
2782     }
2783     case ButtonRelease:
2784     {
2785       if (!IsDragged)
2786       {
2787         VT_ProcessButton3Release();
2788         break;
2789       }
2790
2791       Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
2792       if (aContext.IsNull())
2793       {
2794         std::cout << "Error: No active view.\n";
2795         return 0;
2796       }
2797
2798       if (!DragFirst
2799         && aContext->IsDisplayed (GetRubberBand()))
2800       {
2801         aContext->Remove (GetRubberBand(), Standard_False);
2802         aContext->CurrentViewer()->RedrawImmediate();
2803       }
2804
2805       if (aReport.xbutton.button != Button1)
2806       {
2807         break;
2808       }
2809
2810       const Standard_Boolean isShiftPressed = (aReport.xbutton.state & ShiftMask) != 0;
2811       if (DragFirst)
2812       {
2813         if (isShiftPressed)
2814         {
2815           aContext->ShiftSelect (Standard_True);
2816         }
2817         else
2818         {
2819           aContext->Select (Standard_True);
2820         }
2821       }
2822       else
2823       {
2824         if (isShiftPressed)
2825         {
2826           aContext->ShiftSelect (Min (X_ButtonPress, X_Motion), Min (Y_ButtonPress, Y_Motion),
2827                                  Max (X_ButtonPress, X_Motion), Max (Y_ButtonPress, Y_Motion),
2828                                  ViewerTest::CurrentView(), Standard_True);
2829         }
2830         else
2831         {
2832           aContext->Select (Min (X_ButtonPress, X_Motion), Min(Y_ButtonPress, Y_Motion),
2833                             Max (X_ButtonPress, X_Motion), Max(Y_ButtonPress, Y_Motion),
2834                             ViewerTest::CurrentView(), Standard_True);
2835         }
2836       }
2837       IsDragged = Standard_False;
2838       break;
2839     }
2840     case MotionNotify:
2841     {
2842       Window anXWindow = GetWindowHandle (VT_GetWindow());
2843       if (anXWindow != aReport.xmotion.window)
2844       {
2845         break;
2846       }
2847
2848       // remove all the ButtonMotionMask and process them at once
2849       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
2850       {
2851         if (!XCheckWindowEvent (aDisplay, anXWindow, ButtonMotionMask | PointerMotionMask, &aReport))
2852         {
2853           break;
2854         }
2855       }
2856
2857       if (IsDragged)
2858       {
2859         if (!DragFirst
2860           && ViewerTest::GetAISContext()->IsDisplayed (GetRubberBand()))
2861         {
2862           ViewerTest::GetAISContext()->Remove (GetRubberBand(), Standard_False);
2863         }
2864
2865         X_Motion = aReport.xmotion.x;
2866         Y_Motion = aReport.xmotion.y;
2867         DragFirst = Standard_False;
2868
2869         Window aWindow = GetWindowHandle(VT_GetWindow());
2870         Window aRoot;
2871         int anX, anY;
2872         unsigned int aWidth, aHeight, aBorderWidth, aDepth;
2873         XGetGeometry (aDisplay, aWindow, &aRoot, &anX, &anY, &aWidth, &aHeight, &aBorderWidth, &aDepth);
2874         GetRubberBand()->SetRectangle (X_ButtonPress, aHeight - Y_ButtonPress, X_Motion, aHeight - Y_Motion);
2875         ViewerTest::GetAISContext()->Display (GetRubberBand(), 0, -1, Standard_False, AIS_DS_Displayed);
2876         ViewerTest::GetAISContext()->CurrentViewer()->RedrawImmediate();
2877       }
2878       else
2879       {
2880         X_Motion = aReport.xmotion.x;
2881         Y_Motion = aReport.xmotion.y;
2882         if ((aReport.xmotion.state & ControlMask) != 0)
2883         {
2884           if ((aReport.xmotion.state & Button1Mask) != 0)
2885           {
2886             ProcessControlButton1Motion();
2887           }
2888           else if ((aReport.xmotion.state & Button2Mask) != 0)
2889           {
2890             VT_ProcessControlButton2Motion();
2891           }
2892           else if ((aReport.xmotion.state & Button3Mask) != 0)
2893           {
2894             VT_ProcessControlButton3Motion();
2895           }
2896         }
2897         else
2898         {
2899           VT_ProcessMotion();
2900         }
2901       }
2902       break;
2903     }
2904   }
2905   return (!toPick || toPickMore) ? 1 : 0;
2906 }
2907
2908 //==============================================================================
2909 //function : VProcessEvents
2910 //purpose  : manage the event in the Viewer window (see Tcl_CreateFileHandler())
2911 //==============================================================================
2912 static void VProcessEvents (ClientData theDispX, int)
2913 {
2914   Display* aDispX = (Display* )theDispX;
2915   Handle(Aspect_DisplayConnection) aDispConn;
2916   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(Graphic3d_GraphicDriver)>::Iterator
2917        aDriverIter (ViewerTest_myDrivers); aDriverIter.More(); aDriverIter.Next())
2918   {
2919     const Handle(Aspect_DisplayConnection)& aDispConnTmp = aDriverIter.Key2()->GetDisplayConnection();
2920     if (aDispConnTmp->GetDisplay() == aDispX)
2921     {
2922       aDispConn = aDispConnTmp;
2923       break;
2924     }
2925   }
2926   if (aDispConn.IsNull())
2927   {
2928     std::cerr << "Error: ViewerTest is unable processing messages for unknown X Display\n";
2929     return;
2930   }
2931
2932   // process new events in queue
2933   SetDisplayConnection (aDispConn);
2934   int aNbRemain = 0;
2935   for (int aNbEventsMax = XPending (aDispX), anEventIter (0);;)
2936   {
2937     const int anEventResult = ViewerMainLoop (0, NULL);
2938     if (anEventResult == 0)
2939     {
2940       return;
2941     }
2942
2943     aNbRemain = XPending (aDispX);
2944     if (++anEventIter >= aNbEventsMax
2945      || aNbRemain <= 0)
2946     {
2947       break;
2948     }
2949   }
2950
2951   // Listening X events through Tcl_CreateFileHandler() callback is fragile,
2952   // it is possible that new events will arrive to queue before the end of this callback
2953   // so that either this callback should go into an infinite loop (blocking processing of other events)
2954   // or to keep unprocessed events till the next queue update (which can arrive not soon).
2955   // Sending a dummy event in this case is a simple workaround (still, it is possible that new event will be queued in-between).
2956   if (aNbRemain != 0)
2957   {
2958     XEvent aDummyEvent;
2959     memset (&aDummyEvent, 0, sizeof(aDummyEvent));
2960     aDummyEvent.type = ClientMessage;
2961     aDummyEvent.xclient.format = 32;
2962     XSendEvent (aDispX, InputFocus, False, 0, &aDummyEvent);
2963     XFlush (aDispX);
2964   }
2965
2966   if (const Handle(AIS_InteractiveContext)& anActiveCtx = ViewerTest::GetAISContext())
2967   {
2968     SetDisplayConnection (anActiveCtx->CurrentViewer()->Driver()->GetDisplayConnection());
2969   }
2970 }
2971 #endif
2972
2973 //==============================================================================
2974 //function : OSWindowSetup
2975 //purpose  : Setup for the X11 window to be able to cath the event
2976 //==============================================================================
2977
2978
2979 static void OSWindowSetup()
2980 {
2981 #if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX))
2982   // X11
2983
2984   Window  window   = VT_GetWindow()->XWindow();
2985   SetDisplayConnection (ViewerTest::CurrentView()->Viewer()->Driver()->GetDisplayConnection());
2986   Display *aDisplay = GetDisplayConnection()->GetDisplay();
2987   XSynchronize(aDisplay, 1);
2988
2989   // X11 : For keyboard on SUN
2990   XWMHints wmhints;
2991   wmhints.flags = InputHint;
2992   wmhints.input = 1;
2993
2994   XSetWMHints( aDisplay, window, &wmhints);
2995
2996   XSelectInput( aDisplay, window,  ExposureMask | KeyPressMask |
2997     ButtonPressMask | ButtonReleaseMask |
2998     StructureNotifyMask |
2999     PointerMotionMask |
3000     Button1MotionMask | Button2MotionMask |
3001     Button3MotionMask | FocusChangeMask
3002     );
3003   Atom aDeleteWindowAtom = GetDisplayConnection()->GetAtom(Aspect_XA_DELETE_WINDOW);
3004   XSetWMProtocols(aDisplay, window, &aDeleteWindowAtom, 1);
3005
3006   XSynchronize(aDisplay, 0);
3007
3008 #else
3009   // _WIN32
3010 #endif
3011
3012 }
3013
3014 //==============================================================================
3015 //function : VFit
3016 //purpose  :
3017 //==============================================================================
3018
3019 static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
3020 {
3021   const Handle(V3d_View) aView = ViewerTest::CurrentView();
3022   if (aView.IsNull())
3023   {
3024     std::cout << "Error: no active viewer!\n";
3025     return 1;
3026   }
3027
3028   Standard_Boolean toFit = Standard_True;
3029   ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
3030   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3031   {
3032     TCollection_AsciiString anArg (theArgv[anArgIter]);
3033     anArg.LowerCase();
3034     if (anUpdateTool.parseRedrawMode (anArg))
3035     {
3036       continue;
3037     }
3038     else if (anArg == "-selected")
3039     {
3040       ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
3041       toFit = Standard_False;
3042     }
3043     else
3044     {
3045       std::cout << "Syntax error at '" << anArg << "'\n";
3046     }
3047   }
3048
3049   if (toFit)
3050   {
3051     aView->FitAll (0.01, Standard_False);
3052   }
3053   return 0;
3054 }
3055
3056 //=======================================================================
3057 //function : VFitArea
3058 //purpose  : Fit view to show area located between two points
3059 //         : given in world 2D or 3D coordinates.
3060 //=======================================================================
3061 static int VFitArea (Draw_Interpretor& theDI, Standard_Integer  theArgNb, const char** theArgVec)
3062 {
3063   Handle(V3d_View) aView = ViewerTest::CurrentView();
3064   if (aView.IsNull())
3065   {
3066     std::cerr << theArgVec[0] << "Error: No active view.\n";
3067     return 1;
3068   }
3069
3070   // Parse arguments.
3071   gp_Pnt aWorldPnt1 (0.0, 0.0, 0.0);
3072   gp_Pnt aWorldPnt2 (0.0, 0.0, 0.0);
3073
3074   if (theArgNb == 5)
3075   {
3076     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3077     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3078     aWorldPnt2.SetX (Draw::Atof (theArgVec[3]));
3079     aWorldPnt2.SetY (Draw::Atof (theArgVec[4]));
3080   }
3081   else if (theArgNb == 7)
3082   {
3083     aWorldPnt1.SetX (Draw::Atof (theArgVec[1]));
3084     aWorldPnt1.SetY (Draw::Atof (theArgVec[2]));
3085     aWorldPnt1.SetZ (Draw::Atof (theArgVec[3]));
3086     aWorldPnt2.SetX (Draw::Atof (theArgVec[4]));
3087     aWorldPnt2.SetY (Draw::Atof (theArgVec[5]));
3088     aWorldPnt2.SetZ (Draw::Atof (theArgVec[6]));
3089   }
3090   else
3091   {
3092     std::cerr << theArgVec[0] << "Error: Invalid number of arguments.\n";
3093     theDI.PrintHelp(theArgVec[0]);
3094     return 1;
3095   }
3096
3097   // Convert model coordinates to view space
3098   Handle(Graphic3d_Camera) aCamera = aView->Camera();
3099   gp_Pnt aViewPnt1 = aCamera->ConvertWorld2View (aWorldPnt1);
3100   gp_Pnt aViewPnt2 = aCamera->ConvertWorld2View (aWorldPnt2);
3101
3102   // Determine fit area
3103   gp_Pnt2d aMinCorner (Min (aViewPnt1.X(), aViewPnt2.X()), Min (aViewPnt1.Y(), aViewPnt2.Y()));
3104   gp_Pnt2d aMaxCorner (Max (aViewPnt1.X(), aViewPnt2.X()), Max (aViewPnt1.Y(), aViewPnt2.Y()));
3105
3106   Standard_Real aDiagonal = aMinCorner.Distance (aMaxCorner);
3107
3108   if (aDiagonal < Precision::Confusion())
3109   {
3110     std::cerr << theArgVec[0] << "Error: view area is too small.\n";
3111     return 1;
3112   }
3113
3114   aView->FitAll (aMinCorner.X(), aMinCorner.Y(), aMaxCorner.X(), aMaxCorner.Y());
3115   return 0;
3116 }
3117
3118 //==============================================================================
3119 //function : VZFit
3120 //purpose  : ZFitall, no DRAW arguments
3121 //Draw arg : No args
3122 //==============================================================================
3123 static int VZFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgsNb, const char** theArgVec)
3124 {
3125   const Handle(V3d_View)& aCurrentView = ViewerTest::CurrentView();
3126
3127   if (aCurrentView.IsNull())
3128   {
3129     std::cout << theArgVec[0] << ": Call vinit before this command, please.\n";
3130     return 1;
3131   }
3132
3133   if (theArgsNb == 1)
3134   {
3135     aCurrentView->ZFitAll();
3136     aCurrentView->Redraw();
3137     return 0;
3138   }
3139
3140   Standard_Real aScale = 1.0;
3141
3142   if (theArgsNb >= 2)
3143   {
3144     aScale = Draw::Atoi (theArgVec[1]);
3145   }
3146
3147   aCurrentView->ZFitAll (aScale);
3148   aCurrentView->Redraw();
3149
3150   return 0;
3151 }
3152
3153 //==============================================================================
3154 //function : VRepaint
3155 //purpose  :
3156 //==============================================================================
3157 static int VRepaint (Draw_Interpretor& , Standard_Integer theArgNb, const char** theArgVec)
3158 {
3159   Handle(V3d_View) aView = ViewerTest::CurrentView();
3160   if (aView.IsNull())
3161   {
3162     std::cout << "Error: no active viewer!\n";
3163     return 1;
3164   }
3165
3166   Standard_Boolean isImmediateUpdate = Standard_False;
3167   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
3168   {
3169     TCollection_AsciiString anArg (theArgVec[anArgIter]);
3170     anArg.LowerCase();
3171     if (anArg == "-immediate"
3172      || anArg == "-imm")
3173     {
3174       isImmediateUpdate = Standard_True;
3175       if (anArgIter + 1 < theArgNb
3176        && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], isImmediateUpdate))
3177       {
3178         ++anArgIter;
3179       }
3180     }
3181     else if (anArg == "-continuous"
3182           || anArg == "-cont"
3183           || anArg == "-fps"
3184           || anArg == "-framerate")
3185     {
3186       Standard_Real aFps = -1.0;
3187       if (anArgIter + 1 < theArgNb
3188        && TCollection_AsciiString (theArgVec[anArgIter + 1]).IsRealValue())
3189       {
3190         aFps = Draw::Atof (theArgVec[++anArgIter]);
3191       }
3192
3193       ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
3194       if (Abs (aFps) >= 1.0)
3195       {
3196         aRedrawer.Start (aView->Window(), aFps);
3197       }
3198       else
3199       {
3200         aRedrawer.Stop();
3201       }
3202     }
3203     else
3204     {
3205       std::cout << "Syntax error at '" << anArg << "'\n";
3206       return 1;
3207     }
3208   }
3209
3210   if (isImmediateUpdate)
3211   {
3212     aView->RedrawImmediate();
3213   }
3214   else
3215   {
3216     aView->Redraw();
3217   }
3218   return 0;
3219 }
3220
3221 //==============================================================================
3222 //function : VClear
3223 //purpose  : Remove all the object from the viewer
3224 //Draw arg : No args
3225 //==============================================================================
3226
3227 static int VClear(Draw_Interpretor& , Standard_Integer , const char** )
3228 {
3229   Handle(V3d_View) V = ViewerTest::CurrentView();
3230   if(!V.IsNull())
3231     ViewerTest::Clear();
3232   return 0;
3233 }
3234
3235 //==============================================================================
3236 //function : VPick
3237 //purpose  :
3238 //==============================================================================
3239
3240 static int VPick(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3241 { if (ViewerTest::CurrentView().IsNull() ) return 1;
3242
3243 if ( argc < 4 ) {
3244   di << argv[0] << "Invalid number of arguments\n";
3245   return 1;
3246 }
3247
3248 while (ViewerMainLoop( argc, argv)) {
3249 }
3250
3251 return 0;
3252 }
3253
3254 //==============================================================================
3255 //function : VSetBg
3256 //purpose  : Load image as background
3257 //==============================================================================
3258
3259 static int VSetBg(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3260 {
3261   if (argc < 2 || argc > 3)
3262   {
3263     di << "Usage : " << argv[0] << " imagefile [filltype] : Load image as background\n";
3264     di << "filltype can be one of CENTERED, TILED, STRETCH, NONE\n";
3265     return 1;
3266   }
3267
3268   Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
3269   if(AISContext.IsNull())
3270   {
3271     di << "use 'vinit' command before " << argv[0] << "\n";
3272     return 1;
3273   }
3274
3275   Aspect_FillMethod aFillType = Aspect_FM_CENTERED;
3276   if (argc == 3)
3277   {
3278     const char* szType = argv[2];
3279     if      (strcmp(szType, "NONE"    ) == 0) aFillType = Aspect_FM_NONE;
3280     else if (strcmp(szType, "CENTERED") == 0) aFillType = Aspect_FM_CENTERED;
3281     else if (strcmp(szType, "TILED"   ) == 0) aFillType = Aspect_FM_TILED;
3282     else if (strcmp(szType, "STRETCH" ) == 0) aFillType = Aspect_FM_STRETCH;
3283     else
3284     {
3285       di << "Wrong fill type : " << szType << "\n";
3286       di << "Must be one of CENTERED, TILED, STRETCH, NONE\n";
3287       return 1;
3288     }
3289   }
3290
3291   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3292   V3dView->SetBackgroundImage(argv[1], aFillType, Standard_True);
3293
3294   return 0;
3295 }
3296
3297 //==============================================================================
3298 //function : VSetBgMode
3299 //purpose  : Change background image fill type
3300 //==============================================================================
3301
3302 static int VSetBgMode(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3303 {
3304   if (argc != 2)
3305   {
3306     di << "Usage : " << argv[0] << " filltype : Change background image mode\n";
3307     di << "filltype must be one of CENTERED, TILED, STRETCH, NONE\n";
3308     return 1;
3309   }
3310
3311   Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
3312   if(AISContext.IsNull())
3313   {
3314     di << "use 'vinit' command before " << argv[0] << "\n";
3315     return 1;
3316   }
3317   Aspect_FillMethod aFillType = Aspect_FM_NONE;
3318   const char* szType = argv[1];
3319   if      (strcmp(szType, "NONE"    ) == 0) aFillType = Aspect_FM_NONE;
3320   else if (strcmp(szType, "CENTERED") == 0) aFillType = Aspect_FM_CENTERED;
3321   else if (strcmp(szType, "TILED"   ) == 0) aFillType = Aspect_FM_TILED;
3322   else if (strcmp(szType, "STRETCH" ) == 0) aFillType = Aspect_FM_STRETCH;
3323   else
3324   {
3325     di << "Wrong fill type : " << szType << "\n";
3326     di << "Must be one of CENTERED, TILED, STRETCH, NONE\n";
3327     return 1;
3328   }
3329   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3330   V3dView->SetBgImageStyle(aFillType, Standard_True);
3331   return 0;
3332 }
3333
3334 //==============================================================================
3335 //function : VSetGradientBg
3336 //purpose  : Mount gradient background
3337 //==============================================================================
3338 static int VSetGradientBg(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3339 {
3340   if (argc != 8 )
3341   {
3342     di << "Usage : " << argv[0] << " R1 G1 B1 R2 G2 B2 Type : Mount gradient background\n";
3343     di << "R1,G1,B1,R2,G2,B2 = [0..255]\n";
3344     di << "Type must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
3345     di << "                    5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
3346     return 1;
3347   }
3348
3349   Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
3350   if(AISContext.IsNull())
3351   {
3352     di << "use 'vinit' command before " << argv[0] << "\n";
3353     return 1;
3354   }
3355   if (argc == 8)
3356   {
3357
3358     Standard_Real R1 = Draw::Atof(argv[1])/255.;
3359     Standard_Real G1 = Draw::Atof(argv[2])/255.;
3360     Standard_Real B1 = Draw::Atof(argv[3])/255.;
3361     Quantity_Color aColor1(R1,G1,B1,Quantity_TOC_RGB);
3362
3363     Standard_Real R2 = Draw::Atof(argv[4])/255.;
3364     Standard_Real G2 = Draw::Atof(argv[5])/255.;
3365     Standard_Real B2 = Draw::Atof(argv[6])/255.;
3366
3367     Quantity_Color aColor2(R2,G2,B2,Quantity_TOC_RGB);
3368     int aType = Draw::Atoi(argv[7]);
3369     if( aType < 0 || aType > 8 )
3370     {
3371       di << "Wrong fill type \n";
3372       di << "Must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
3373       di << "               5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
3374       return 1;
3375     }
3376
3377     Aspect_GradientFillMethod aMethod = Aspect_GradientFillMethod(aType);
3378
3379     Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3380     V3dView->SetBgGradientColors( aColor1, aColor2, aMethod, 1);
3381   }
3382
3383   return 0;
3384 }
3385
3386 //==============================================================================
3387 //function : VSetGradientBgMode
3388 //purpose  : Change gradient background fill style
3389 //==============================================================================
3390 static int VSetGradientBgMode(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3391 {
3392   if (argc != 2 )
3393   {
3394     di << "Usage : " << argv[0] << " Type : Change gradient background fill type\n";
3395     di << "Type must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
3396     di << "                    5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
3397     return 1;
3398   }
3399
3400   Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
3401   if(AISContext.IsNull())
3402   {
3403     di << "use 'vinit' command before " << argv[0] << "\n";
3404     return 1;
3405   }
3406   if (argc == 2)
3407   {
3408     int aType = Draw::Atoi(argv[1]);
3409     if( aType < 0 || aType > 8 )
3410     {
3411       di << "Wrong fill type \n";
3412       di << "Must be one of 0 = NONE, 1 = HOR, 2 = VER, 3 = DIAG1, 4 = DIAG2\n";
3413       di << "               5 = CORNER1, 6 = CORNER2, 7 = CORNER3, 8 = CORNER4\n";
3414       return 1;
3415     }
3416
3417     Aspect_GradientFillMethod aMethod = Aspect_GradientFillMethod(aType);
3418
3419     Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3420     V3dView->SetBgGradientStyle( aMethod, 1 );
3421   }
3422
3423   return 0;
3424 }
3425
3426 //==============================================================================
3427 //function : VSetColorBg
3428 //purpose  : Set color background
3429 //==============================================================================
3430 static int VSetColorBg(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3431 {
3432   if (argc != 4 )
3433   {
3434     di << "Usage : " << argv[0] << " R G B : Set color background\n";
3435     di << "R,G,B = [0..255]\n";
3436     return 1;
3437   }
3438
3439   Handle(AIS_InteractiveContext) AISContext = ViewerTest::GetAISContext();
3440   if(AISContext.IsNull())
3441   {
3442     di << "use 'vinit' command before " << argv[0] << "\n";
3443     return 1;
3444   }
3445   if (argc == 4)
3446   {
3447
3448     Standard_Real R = Draw::Atof(argv[1])/255.;
3449     Standard_Real G = Draw::Atof(argv[2])/255.;
3450     Standard_Real B = Draw::Atof(argv[3])/255.;
3451     Quantity_Color aColor(R,G,B,Quantity_TOC_RGB);
3452
3453     Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3454     V3dView->SetBackgroundColor( aColor );
3455     V3dView->Update();
3456   }
3457
3458   return 0;
3459 }
3460
3461 //==============================================================================
3462 //function : VSetDefaultBg
3463 //purpose  : Set default viewer background fill color
3464 //==============================================================================
3465 static int VSetDefaultBg (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
3466 {
3467   if (theArgNb != 4
3468    && theArgNb != 8)
3469   {
3470     std::cout << "Error: wrong syntax! See usage:\n";
3471     theDI.PrintHelp (theArgVec[0]);
3472     return 1;
3473   }
3474
3475   ViewerTest_DefaultBackground.FillMethod =
3476     theArgNb == 4 ? Aspect_GFM_NONE
3477                   : (Aspect_GradientFillMethod) Draw::Atoi (theArgVec[7]);
3478
3479   if (theArgNb == 4)
3480   {
3481     Standard_Real R = Draw::Atof (theArgVec[1]) / 255.;
3482     Standard_Real G = Draw::Atof (theArgVec[2]) / 255.;
3483     Standard_Real B = Draw::Atof (theArgVec[3]) / 255.;
3484     ViewerTest_DefaultBackground.FlatColor.SetValues (R, G, B, Quantity_TOC_RGB);
3485   }
3486   else
3487   {
3488     Standard_Real R1 = Draw::Atof (theArgVec[1]) / 255.;
3489     Standard_Real G1 = Draw::Atof (theArgVec[2]) / 255.;
3490     Standard_Real B1 = Draw::Atof (theArgVec[3]) / 255.;
3491     ViewerTest_DefaultBackground.GradientColor1.SetValues (R1, G1, B1, Quantity_TOC_RGB);
3492
3493     Standard_Real R2 = Draw::Atof (theArgVec[4]) / 255.;
3494     Standard_Real G2 = Draw::Atof (theArgVec[5]) / 255.;
3495     Standard_Real B2 = Draw::Atof (theArgVec[6]) / 255.;
3496     ViewerTest_DefaultBackground.GradientColor2.SetValues (R2, G2, B2, Quantity_TOC_RGB);
3497   }
3498
3499   for (NCollection_DoubleMap<TCollection_AsciiString, Handle(AIS_InteractiveContext)>::Iterator
3500        anIter (ViewerTest_myContexts); anIter.More(); anIter.Next())
3501   {
3502     const Handle(V3d_Viewer)& aViewer = anIter.Value()->CurrentViewer();
3503     aViewer->SetDefaultBackgroundColor (ViewerTest_DefaultBackground.FlatColor);
3504     aViewer->SetDefaultBgGradientColors (ViewerTest_DefaultBackground.GradientColor1,
3505                                          ViewerTest_DefaultBackground.GradientColor2,
3506                                          ViewerTest_DefaultBackground.FillMethod);
3507   }
3508
3509   return 0;
3510 }
3511
3512 //==============================================================================
3513 //function : VScale
3514 //purpose  : View Scaling
3515 //==============================================================================
3516
3517 static int VScale(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
3518 {
3519   Handle(V3d_View) V3dView = ViewerTest::CurrentView();
3520   if ( V3dView.IsNull() ) return 1;
3521
3522   if ( argc != 4 ) {
3523     di << argv[0] << "Invalid number of arguments\n";