0031620: Samples - update Android JNI sample to use AIS_ViewController
[occt.git] / samples / java / jniviewer / app / src / main / jni / OcctJni_Viewer.cxx
1 // Copyright (c) 2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include "OcctJni_Viewer.hxx"
15 #include "OcctJni_MsgPrinter.hxx"
16
17 #include <AIS_ViewCube.hxx>
18 #include <AIS_Shape.hxx>
19 #include <Aspect_NeutralWindow.hxx>
20 #include <Image_AlienPixMap.hxx>
21 #include <BRepTools.hxx>
22 #include <Message_Messenger.hxx>
23 #include <Message_MsgFile.hxx>
24 #include <Message_PrinterSystemLog.hxx>
25 #include <OpenGl_GraphicDriver.hxx>
26 #include <OSD_Environment.hxx>
27 #include <OSD_Timer.hxx>
28 #include <Prs3d_DatumAspect.hxx>
29 #include <Standard_Version.hxx>
30
31 #include <BRepPrimAPI_MakeBox.hxx>
32
33 #include <STEPControl_Reader.hxx>
34 #include <IGESControl_Reader.hxx>
35 #include <XSControl_WorkSession.hxx>
36
37 #include <EGL/egl.h>
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41
42 #include <jni.h>
43
44 //! @return true if file exists
45 static bool isFileExist (const TCollection_AsciiString& thePath)
46 {
47   struct stat64 aStatBuffer;
48   return stat64 (thePath.ToCString(), &aStatBuffer) == 0;
49 }
50
51 //! Cut-off the last split character from the path and everything after it.
52 static TCollection_AsciiString getParentDir (const TCollection_AsciiString& thePath)
53 {
54   TCollection_AsciiString aPath = thePath;
55   char* aSplitter = (char* )aPath.ToCString();
56   for (char* anIter = aSplitter; *anIter != '\0'; ++anIter)
57   {
58     if (*anIter == '\\'
59      || *anIter == '/')
60     {
61       aSplitter = anIter;
62     }
63   }
64   *aSplitter = '\0'; // cut off file name or trailing folder
65   return TCollection_AsciiString (aPath.ToCString());
66 }
67
68 //! Set environment variable theVarName indicating location of resource
69 //! file theFile so as to correspond to actual location of this file.
70 //!
71 //! The resource file is searched in directory where Test.Draw.dll is located,
72 //! and if not found - also in subdirectory ../res from there.
73 //! If file is found, environment variable is set for C subsystem.
74 //! Otherwise, environment is not changed.
75 //!
76 //! If theToAddFileName is true, complete file name is set as value of the variable,
77 //! if theToAddFileName is false, only path is set.
78 Standard_Boolean setResourceEnv (const TCollection_AsciiString& theVarName,
79                                  const TCollection_AsciiString& theRoot,
80                                  const TCollection_AsciiString& theFile,
81                                  const Standard_Boolean         theToAddFileName)
82 {
83   // use location of current assembly to figure out possible location of resource
84   TCollection_AsciiString aBaseDir = theRoot;
85
86   // check the same directory where binary is located
87   if (!isFileExist (aBaseDir + "/" + theFile))
88   {
89     // check subdirectory ../res
90     aBaseDir = getParentDir (aBaseDir) + "/res";
91     if (!isFileExist (aBaseDir + "/" + theFile))
92     {
93       return Standard_False;
94     }
95   }
96
97   // set C library environment
98   if (theToAddFileName)
99   {
100     aBaseDir = aBaseDir + "/" + theFile;
101   }
102
103   OSD_Environment anEnv (theVarName, aBaseDir);
104   anEnv.Build();
105   return Standard_True;
106 }
107
108 // =======================================================================
109 // function : OcctJni_Viewer
110 // purpose  :
111 // =======================================================================
112 OcctJni_Viewer::OcctJni_Viewer (float theDispDensity)
113 : myDevicePixelRatio (theDispDensity),
114   myIsJniMoreFrames (false)
115 {
116   SetTouchToleranceScale (theDispDensity);
117 #ifndef NDEBUG
118   // Register printer for logging messages into global Android log.
119   // Should never be used in production (or specify higher gravity for logging only failures).
120   Handle(Message_Messenger) aMsgMgr = Message::DefaultMessenger();
121   aMsgMgr->RemovePrinters (STANDARD_TYPE (Message_PrinterSystemLog));
122   aMsgMgr->AddPrinter (new Message_PrinterSystemLog ("OcctJni_Viewer"));
123 #endif
124
125   // prepare necessary environment
126   TCollection_AsciiString aResRoot = "/data/data/com.opencascade.jnisample/files";
127
128   setResourceEnv ("CSF_XSMessage", aResRoot + "/XSMessage", "XSTEP.us", Standard_False);
129   setResourceEnv ("CSF_SHMessage", aResRoot + "/XSMessage", "SHAPE.us", Standard_False);
130 }
131
132 // ================================================================
133 // Function : dumpGlInfo
134 // Purpose  :
135 // ================================================================
136 void OcctJni_Viewer::dumpGlInfo (bool theIsBasic)
137 {
138   TColStd_IndexedDataMapOfStringString aGlCapsDict;
139   myView->DiagnosticInformation (aGlCapsDict, Graphic3d_DiagnosticInfo_Basic); //theIsBasic ? Graphic3d_DiagnosticInfo_Basic : Graphic3d_DiagnosticInfo_Complete);
140   if (theIsBasic)
141   {
142     TCollection_AsciiString aViewport;
143     aGlCapsDict.FindFromKey ("Viewport", aViewport);
144     aGlCapsDict.Clear();
145     aGlCapsDict.Add ("Viewport", aViewport);
146   }
147   aGlCapsDict.Add ("Display scale", TCollection_AsciiString(myDevicePixelRatio));
148
149   // beautify output
150   {
151     TCollection_AsciiString* aGlVer   = aGlCapsDict.ChangeSeek ("GLversion");
152     TCollection_AsciiString* aGlslVer = aGlCapsDict.ChangeSeek ("GLSLversion");
153     if (aGlVer   != NULL
154      && aGlslVer != NULL)
155     {
156       *aGlVer = *aGlVer + " [GLSL: " + *aGlslVer + "]";
157       aGlslVer->Clear();
158     }
159   }
160
161   TCollection_AsciiString anInfo;
162   for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aGlCapsDict); aValueIter.More(); aValueIter.Next())
163   {
164     if (!aValueIter.Value().IsEmpty())
165     {
166       if (!anInfo.IsEmpty())
167       {
168         anInfo += "\n";
169       }
170       anInfo += aValueIter.Key() + ": " + aValueIter.Value();
171     }
172   }
173
174   Message::Send (anInfo, Message_Warning);
175 }
176
177 // =======================================================================
178 // function : init
179 // purpose  :
180 // =======================================================================
181 bool OcctJni_Viewer::init()
182 {
183   EGLint aCfgId = 0;
184   int aWidth = 0, aHeight = 0;
185   EGLDisplay anEglDisplay = eglGetCurrentDisplay();
186   EGLContext anEglContext = eglGetCurrentContext();
187   EGLSurface anEglSurf    = eglGetCurrentSurface (EGL_DRAW);
188   if (anEglDisplay == EGL_NO_DISPLAY
189    || anEglContext == EGL_NO_CONTEXT
190    || anEglSurf    == EGL_NO_SURFACE)
191   {
192     Message::DefaultMessenger()->Send ("Error: No active EGL context!", Message_Fail);
193     release();
194     return false;
195   }
196
197   eglQuerySurface (anEglDisplay, anEglSurf, EGL_WIDTH,     &aWidth);
198   eglQuerySurface (anEglDisplay, anEglSurf, EGL_HEIGHT,    &aHeight);
199   eglQuerySurface (anEglDisplay, anEglSurf, EGL_CONFIG_ID, &aCfgId);
200   const EGLint aConfigAttribs[] = { EGL_CONFIG_ID, aCfgId, EGL_NONE };
201   EGLint       aNbConfigs = 0;
202   void*        anEglConfig = NULL;
203   if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) != EGL_TRUE)
204   {
205     Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations!", Message_Fail);
206     release();
207     return false;
208   }
209
210   if (!myViewer.IsNull())
211   {
212     Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
213     Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast (myView->Window());
214     if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig))
215     {
216       Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized!", Message_Fail);
217       release();
218       return false;
219     }
220
221     aWindow->SetSize (aWidth, aHeight);
222     myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
223     dumpGlInfo (true);
224     return true;
225   }
226
227   Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (NULL, Standard_False);
228   aDriver->ChangeOptions().buffersNoSwap = Standard_True;
229 //aDriver->ChangeOptions().glslWarnings  = Standard_True; /// for debug only!
230   if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig))
231   {
232     Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized!", Message_Fail);
233     release();
234     return false;
235   }
236
237   myTextStyle = new Prs3d_TextAspect();
238   myTextStyle->SetFont (Font_NOF_ASCII_MONO);
239   myTextStyle->SetHeight (12);
240   myTextStyle->Aspect()->SetColor (Quantity_NOC_GRAY95);
241   myTextStyle->Aspect()->SetColorSubTitle (Quantity_NOC_BLACK);
242   myTextStyle->Aspect()->SetDisplayType (Aspect_TODT_SHADOW);
243   myTextStyle->Aspect()->SetTextFontAspect (Font_FA_Bold);
244   myTextStyle->Aspect()->SetTextZoomable (false);
245   myTextStyle->SetHorizontalJustification (Graphic3d_HTA_LEFT);
246   myTextStyle->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
247
248   // create viewer
249   myViewer = new V3d_Viewer (aDriver);
250   myViewer->SetDefaultBackgroundColor (Quantity_NOC_BLACK);
251   myViewer->SetDefaultLights();
252   myViewer->SetLightOn();
253
254   // create AIS context
255   myContext = new AIS_InteractiveContext (myViewer);
256   myContext->SetPixelTolerance (int(myDevicePixelRatio * 6.0)); // increase tolerance and adjust to hi-dpi screens
257   myContext->SetDisplayMode (AIS_Shaded, false);
258
259   Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow();
260   aWindow->SetSize (aWidth, aHeight);
261   myView = myViewer->CreateView();
262   myView->SetImmediateUpdate (false);
263   myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5);
264   myView->ChangeRenderingParams().ToShowStats = true;
265   myView->ChangeRenderingParams().CollectedStats = (Graphic3d_RenderingParams::PerfCounters ) (Graphic3d_RenderingParams::PerfCounters_FrameRate | Graphic3d_RenderingParams::PerfCounters_Triangles);
266   myView->ChangeRenderingParams().StatsTextAspect = myTextStyle->Aspect();
267   myView->ChangeRenderingParams().StatsTextHeight = (int )myTextStyle->Height();
268
269   myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
270   dumpGlInfo (false);
271   //myView->TriedronDisplay (Aspect_TOTP_RIGHT_LOWER, Quantity_NOC_WHITE, 0.08 * myDevicePixelRatio, V3d_ZBUFFER);
272
273   initContent();
274   return true;
275 }
276
277 // =======================================================================
278 // function : release
279 // purpose  :
280 // =======================================================================
281 void OcctJni_Viewer::release()
282 {
283   myContext.Nullify();
284   myView.Nullify();
285   myViewer.Nullify();
286 }
287
288 // =======================================================================
289 // function : resize
290 // purpose  :
291 // =======================================================================
292 void OcctJni_Viewer::resize (int theWidth,
293                              int theHeight)
294 {
295   if (myContext.IsNull())
296   {
297     Message::DefaultMessenger()->Send ("Resize failed - view is unavailable", Message_Fail);
298     return;
299   }
300
301   Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
302   Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast (myView->Window());
303   aWindow->SetSize (theWidth, theHeight);
304   //myView->MustBeResized(); // can be used instead of SetWindow() when EGLsurface has not been changed
305
306   EGLContext anEglContext = eglGetCurrentContext();
307   myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
308   dumpGlInfo (true);
309   //saveSnapshot ("/sdcard/Download/tt.png", theWidth, theHeight);
310 }
311
312 // =======================================================================
313 // function : initContent
314 // purpose  :
315 // =======================================================================
316 void OcctJni_Viewer::initContent()
317 {
318   myContext->RemoveAll (Standard_False);
319
320   if (myViewCube.IsNull())
321   {
322     myViewCube = new AIS_ViewCube();
323     {
324       // setup view cube size
325       static const double THE_CUBE_SIZE = 60.0;
326       myViewCube->SetSize (myDevicePixelRatio * THE_CUBE_SIZE, false);
327       myViewCube->SetBoxFacetExtension (myViewCube->Size() * 0.15);
328       myViewCube->SetAxesPadding (myViewCube->Size() * 0.10);
329       myViewCube->SetFontHeight  (THE_CUBE_SIZE * 0.16);
330     }
331     // presentation parameters
332     myViewCube->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_RIGHT_LOWER, Graphic3d_Vec2i (200, 200)));
333     myViewCube->Attributes()->SetDatumAspect (new Prs3d_DatumAspect());
334     myViewCube->Attributes()->DatumAspect()->SetTextAspect (myTextStyle);
335     // animation parameters
336     myViewCube->SetViewAnimation (myViewAnimation);
337     myViewCube->SetFixedAnimationLoop (false);
338     myViewCube->SetAutoStartAnimation (true);
339   }
340   myContext->Display (myViewCube, false);
341
342   OSD_Timer aTimer;
343   aTimer.Start();
344   if (!myShape.IsNull())
345   {
346     Handle(AIS_Shape) aShapePrs = new AIS_Shape (myShape);
347     myContext->Display (aShapePrs, Standard_False);
348   }
349   else
350   {
351     BRepPrimAPI_MakeBox aBuilder (1.0, 2.0, 3.0);
352     Handle(AIS_Shape) aShapePrs = new AIS_Shape (aBuilder.Shape());
353     myContext->Display (aShapePrs, Standard_False);
354   }
355   myView->FitAll();
356
357   aTimer.Stop();
358   Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Presentation computed in " + aTimer.ElapsedTime() + " seconds", Message_Info);
359 }
360
361 //! Load shape from IGES file
362 static TopoDS_Shape loadIGES (const TCollection_AsciiString& thePath)
363 {
364   TopoDS_Shape          aShape;
365   IGESControl_Reader    aReader;
366   IFSelect_ReturnStatus aReadStatus = IFSelect_RetFail;
367   try
368   {
369     aReadStatus = aReader.ReadFile (thePath.ToCString());
370   }
371   catch (Standard_Failure)
372   {
373     Message::DefaultMessenger()->Send ("Error: IGES reader, computation error", Message_Fail);
374     return aShape;
375   }
376
377   if (aReadStatus != IFSelect_RetDone)
378   {
379     Message::DefaultMessenger()->Send ("Error: IGES reader, bad file format", Message_Fail);
380     return aShape;
381   }
382
383   // now perform the translation
384   aReader.TransferRoots();
385   if (aReader.NbShapes() <= 0)
386   {
387     Handle(XSControl_WorkSession) aWorkSession = new XSControl_WorkSession();
388     aWorkSession->SelectNorm ("IGES");
389     aReader.SetWS (aWorkSession, Standard_True);
390     aReader.SetReadVisible (Standard_False);
391     aReader.TransferRoots();
392   }
393   if (aReader.NbShapes() <= 0)
394   {
395     Message::DefaultMessenger()->Send ("Error: IGES reader, no shapes has been found", Message_Fail);
396     return aShape;
397   }
398   return aReader.OneShape();
399   /*TopoDS_Shape anImportedShape = aReader.OneShape();
400
401   // apply sewing on the imported shape
402   BRepBuilderAPI_Sewing aTool (0.0);
403   aTool.SetNonManifoldMode  (Standard_False);
404   aTool.SetFloatingEdgesMode(Standard_True);
405   aTool.Load (anImportedShape);
406   aTool.Perform();
407   TopoDS_Shape aSewedShape = aTool.SewedShape();
408
409   if (aSewedShape.IsNull())
410   {
411     Message::DefaultMessenger()->Send ("Error: Sewing result is empty", Message_Fail);
412     return aShape;
413   }
414   if (aSewedShape.IsSame(anImportedShape))
415   {
416     aShape = anImportedShape;
417   }
418   else
419   {
420     // apply shape healing
421     ShapeFix_Shape aShapeFixer(aSewedShape);
422     aShapeFixer.FixSolidMode() = 1;
423     aShapeFixer.FixFreeShellMode() = 1;
424     aShapeFixer.FixFreeFaceMode() = 1;
425     aShapeFixer.FixFreeWireMode() = 0;
426     aShapeFixer.FixSameParameterMode() = 0;
427     aShapeFixer.FixVertexPositionMode() = 0;
428     aShape = aShapeFixer.Perform() ? aShapeFixer.Shape() : aSewedShape;
429   }
430   return aShape;*/
431 }
432
433 //! Load shape from STEP file
434 static TopoDS_Shape loadSTEP (const TCollection_AsciiString& thePath)
435 {
436   STEPControl_Reader    aReader;
437   IFSelect_ReturnStatus aReadStatus = IFSelect_RetFail;
438   try
439   {
440     aReadStatus = aReader.ReadFile (thePath.ToCString());
441   }
442   catch (Standard_Failure)
443   {
444     Message::DefaultMessenger()->Send ("Error: STEP reader, computation error", Message_Fail);
445     return TopoDS_Shape();
446   }
447
448   if (aReadStatus != IFSelect_RetDone)
449   {
450     Message::DefaultMessenger()->Send ("Error: STEP reader, bad file format", Message_Fail);
451     return TopoDS_Shape();
452   }
453   else if (aReader.NbRootsForTransfer() <= 0)
454   {
455     Message::DefaultMessenger()->Send ("Error: STEP reader, shape is empty", Message_Fail);
456     return TopoDS_Shape();
457   }
458
459   // now perform the translation
460   aReader.TransferRoots();
461   return aReader.OneShape();
462 }
463
464 // =======================================================================
465 // function : open
466 // purpose  :
467 // =======================================================================
468 bool OcctJni_Viewer::open (const TCollection_AsciiString& thePath)
469 {
470   myShape.Nullify();
471   if (!myContext.IsNull())
472   {
473     myContext->RemoveAll (Standard_False);
474     if (!myViewCube.IsNull())
475     {
476       myContext->Display (myViewCube, false);
477     }
478   }
479   if (thePath.IsEmpty())
480   {
481     return false;
482   }
483
484   OSD_Timer aTimer;
485   aTimer.Start();
486   TCollection_AsciiString aFormatStr;
487   const Standard_Integer  aLen = thePath.Length();
488   if (aLen >= 5
489   && thePath.Value (aLen - 4) == '.')
490   {
491     aFormatStr = thePath.SubString (aLen - 3, aLen);
492   }
493   else if (aLen >= 4
494    && thePath.Value (aLen - 3) == '.')
495   {
496     aFormatStr = thePath.SubString (aLen - 2, aLen);
497   }
498   else if (aLen >= 3
499         && thePath.Value (aLen - 2) == '.')
500   {
501     aFormatStr = thePath.SubString (aLen - 1, aLen);
502   }
503   aFormatStr.LowerCase();
504
505   TopoDS_Shape aShape;
506   if (aFormatStr == "stp"
507    || aFormatStr == "step")
508   {
509     aShape = loadSTEP (thePath);
510   }
511   else if (aFormatStr == "igs"
512         || aFormatStr == "iges")
513   {
514     aShape = loadIGES (thePath);
515   }
516   else
517       // if (aFormatStr == "brep"
518       //  || aFormatStr == "rle")
519   {
520     BRep_Builder aBuilder;
521     if (!BRepTools::Read (aShape, thePath.ToCString(), aBuilder))
522     {
523       Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Error: file '" + thePath + "' can not be opened!", Message_Info);
524       return false;
525     }
526   }
527   if (aShape.IsNull())
528   {
529     return false;
530   }
531   aTimer.Stop();
532   Message::DefaultMessenger()->Send (TCollection_AsciiString() + "File '" + thePath + "' loaded in " + aTimer.ElapsedTime() + " seconds", Message_Info);
533
534   myShape = aShape;
535   if (myContext.IsNull())
536   {
537     return true;
538   }
539
540   aTimer.Reset();
541   aTimer.Start();
542
543   Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape);
544   myContext->Display (aShapePrs, Standard_False);
545   myView->FitAll();
546
547   aTimer.Stop();
548   Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Presentation computed in " + aTimer.ElapsedTime() + " seconds", Message_Info);
549   return true;
550 }
551
552 // =======================================================================
553 // function : saveSnapshot
554 // purpose  :
555 // =======================================================================
556 bool OcctJni_Viewer::saveSnapshot (const TCollection_AsciiString& thePath,
557                                    int theWidth,
558                                    int theHeight)
559 {
560   if (myContext.IsNull()
561    || thePath.IsEmpty())
562   {
563     Message::DefaultMessenger()->Send ("Image dump failed - view is unavailable", Message_Fail);
564     return false;
565   }
566
567   if (theWidth  < 1
568    || theHeight < 1)
569   {
570     myView->Window()->Size (theWidth, theHeight);
571   }
572   if (theWidth  < 1
573    || theHeight < 1)
574   {
575     Message::DefaultMessenger()->Send ("Image dump failed - view is unavailable", Message_Fail);
576     return false;
577   }
578
579   Image_AlienPixMap anAlienImage;
580   if (!anAlienImage.InitTrash (Image_PixMap::ImgBGRA, theWidth, theHeight))
581   {
582     Message::DefaultMessenger()->Send (TCollection_AsciiString() + "RGBA image " + theWidth + "x" + theHeight + " allocation failed", Message_Fail);
583     return false;
584   }
585
586   // OpenGL ES does not support fetching data in BGRA format
587   // while FreeImage does not support RGBA format.
588   Image_PixMap anImage;
589   anImage.InitWrapper (Image_PixMap::ImgRGBA,
590                        anAlienImage.ChangeData(),
591                        anAlienImage.SizeX(),
592                        anAlienImage.SizeY(),
593                        anAlienImage.SizeRowBytes());
594   if (!myView->ToPixMap (anImage, theWidth, theHeight, Graphic3d_BT_RGBA))
595   {
596     Message::DefaultMessenger()->Send (TCollection_AsciiString() + "View dump to the image " + theWidth + "x" + theHeight + " failed", Message_Fail);
597   }
598
599   for (Standard_Size aRow = 0; aRow < anAlienImage.SizeY(); ++aRow)
600   {
601     for (Standard_Size aCol = 0; aCol < anAlienImage.SizeX(); ++aCol)
602     {
603       Image_ColorRGBA& aPixel = anAlienImage.ChangeValue<Image_ColorRGBA> (aRow, aCol);
604       std::swap (aPixel.r(), aPixel.b());
605       //aPixel.a() = 1.0;
606     }
607   }
608
609   if (!anAlienImage.Save (thePath))
610   {
611     Message::DefaultMessenger()->Send (TCollection_AsciiString() + "Image saving to path '" + thePath + "' failed", Message_Fail);
612     return false;
613   }
614   Message::DefaultMessenger()->Send (TCollection_AsciiString() + "View " + theWidth + "x" + theHeight + " dumped to image '" + thePath + "'", Message_Info);
615   return true;
616 }
617
618 // ================================================================
619 // Function : handleViewRedraw
620 // Purpose  :
621 // ================================================================
622 void OcctJni_Viewer::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
623                                        const Handle(V3d_View)& theView)
624 {
625   AIS_ViewController::handleViewRedraw (theCtx, theView);
626   myIsJniMoreFrames = myToAskNextFrame;
627 }
628
629 // =======================================================================
630 // function : redraw
631 // purpose  :
632 // =======================================================================
633 bool OcctJni_Viewer::redraw()
634 {
635   if (myView.IsNull())
636   {
637     return false;
638   }
639
640   // handle user input
641   myIsJniMoreFrames = false;
642   myView->InvalidateImmediate();
643   FlushViewEvents (myContext, myView, true);
644   return myIsJniMoreFrames;
645 }
646
647 // =======================================================================
648 // function : fitAll
649 // purpose  :
650 // =======================================================================
651 void OcctJni_Viewer::fitAll()
652 {
653   if (myView.IsNull())
654   {
655     return;
656   }
657
658   myView->FitAll (0.01, Standard_False);
659   myView->Invalidate();
660 }
661
662 #define jexp extern "C" JNIEXPORT
663
664 jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppCreate (JNIEnv* theEnv,
665                                                                              jobject theObj,
666                                                                              jfloat  theDispDensity)
667 {
668   return jlong(new OcctJni_Viewer (theDispDensity));
669 }
670
671 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppDestroy (JNIEnv* theEnv,
672                                                                              jobject theObj,
673                                                                              jlong   theCppPtr)
674 {
675   delete (OcctJni_Viewer* )theCppPtr;
676
677   Handle(Message_Messenger) aMsgMgr = Message::DefaultMessenger();
678   aMsgMgr->RemovePrinters (STANDARD_TYPE (OcctJni_MsgPrinter));
679 }
680
681 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRelease (JNIEnv* theEnv,
682                                                                              jobject theObj,
683                                                                              jlong   theCppPtr)
684 {
685   ((OcctJni_Viewer* )theCppPtr)->release();
686 }
687
688 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppInit (JNIEnv* theEnv,
689                                                                           jobject theObj,
690                                                                           jlong   theCppPtr)
691 {
692   Handle(Message_Messenger) aMsgMgr = Message::DefaultMessenger();
693   aMsgMgr->RemovePrinters (STANDARD_TYPE (OcctJni_MsgPrinter));
694   aMsgMgr->AddPrinter (new OcctJni_MsgPrinter (theEnv, theObj));
695   ((OcctJni_Viewer* )theCppPtr)->init();
696 }
697
698 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppResize (JNIEnv* theEnv,
699                                                                             jobject theObj,
700                                                                             jlong   theCppPtr,
701                                                                             jint    theWidth,
702                                                                             jint    theHeight)
703 {
704   ((OcctJni_Viewer* )theCppPtr)->resize (theWidth, theHeight);
705 }
706
707 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppOpen (JNIEnv* theEnv,
708                                                                           jobject theObj,
709                                                                           jlong   theCppPtr,
710                                                                           jstring thePath)
711 {
712   const char* aPathPtr = theEnv->GetStringUTFChars (thePath, 0);
713   const TCollection_AsciiString aPath (aPathPtr);
714   theEnv->ReleaseStringUTFChars (thePath, aPathPtr);
715   ((OcctJni_Viewer* )theCppPtr)->open (aPath);
716 }
717
718 jexp jboolean JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRedraw (JNIEnv* theEnv,
719                                                                                 jobject theObj,
720                                                                                 jlong   theCppPtr)
721 {
722   return ((OcctJni_Viewer* )theCppPtr)->redraw() ? JNI_TRUE : JNI_FALSE;
723 }
724
725 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetAxoProj (JNIEnv* theEnv,
726                                                                                 jobject theObj,
727                                                                                 jlong   theCppPtr)
728 {
729   ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_XposYnegZpos);
730 }
731
732 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetXposProj (JNIEnv* theEnv,
733                                                                                  jobject theObj,
734                                                                                  jlong   theCppPtr)
735 {
736   ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Xpos);
737 }
738
739 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetYposProj (JNIEnv* theEnv,
740                                                                                  jobject theObj,
741                                                                                  jlong   theCppPtr)
742 {
743   ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Ypos);
744 }
745
746 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetZposProj (JNIEnv* theEnv,
747                                                                                  jobject theObj,
748                                                                                  jlong   theCppPtr)
749 {
750   ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Zpos);
751 }
752
753 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetXnegProj (JNIEnv* theEnv,
754                                                                                  jobject theObj,
755                                                                                  jlong   theCppPtr)
756 {
757   ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Xneg);
758 }
759
760 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetYnegProj (JNIEnv* theEnv,
761                                                                                  jobject theObj,
762                                                                                  jlong   theCppPtr)
763 {
764   ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Yneg);
765 }
766
767 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSetZnegProj (JNIEnv* theEnv,
768                                                                                  jobject theObj,
769                                                                                  jlong   theCppPtr)
770 {
771   ((OcctJni_Viewer* )theCppPtr)->setProj (V3d_Zneg);
772 }
773
774 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppFitAll (JNIEnv* theEnv,
775                                                                             jobject theObj,
776                                                                             jlong   theCppPtr)
777 {
778   ((OcctJni_Viewer* )theCppPtr)->fitAll();
779 }
780
781 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppAddTouchPoint (JNIEnv* theEnv,
782                                                                                    jobject theObj,
783                                                                                    jlong   theCppPtr,
784                                                                                    jint    theId,
785                                                                                    jfloat  theX,
786                                                                                    jfloat  theY)
787 {
788   ((OcctJni_Viewer* )theCppPtr)->AddTouchPoint (theId, Graphic3d_Vec2d (theX, theY));
789 }
790
791 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppUpdateTouchPoint (JNIEnv* theEnv,
792                                                                                    jobject theObj,
793                                                                                    jlong   theCppPtr,
794                                                                                    jint    theId,
795                                                                                    jfloat  theX,
796                                                                                    jfloat  theY)
797 {
798   ((OcctJni_Viewer* )theCppPtr)->UpdateTouchPoint (theId, Graphic3d_Vec2d (theX, theY));
799 }
800
801 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppRemoveTouchPoint (JNIEnv* theEnv,
802                                                                                    jobject theObj,
803                                                                                    jlong   theCppPtr,
804                                                                                    jint    theId)
805 {
806   ((OcctJni_Viewer* )theCppPtr)->RemoveTouchPoint (theId);
807 }
808
809 jexp void JNICALL Java_com_opencascade_jnisample_OcctJniRenderer_cppSelectInViewer (JNIEnv* theEnv,
810                                                                                     jobject theObj,
811                                                                                     jlong   theCppPtr,
812                                                                                     jfloat  theX,
813                                                                                     jfloat  theY)
814 {
815   ((OcctJni_Viewer* )theCppPtr)->SelectInViewer (Graphic3d_Vec2i ((int )theX, (int )theY));
816 }
817
818 jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniActivity_cppOcctMajorVersion (JNIEnv* theEnv,
819                                                                                        jobject theObj)
820 {
821   return OCC_VERSION_MAJOR;
822 }
823
824 jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniActivity_cppOcctMinorVersion (JNIEnv* theEnv,
825                                                                                        jobject theObj)
826 {
827   return OCC_VERSION_MINOR;
828 }
829
830 jexp jlong JNICALL Java_com_opencascade_jnisample_OcctJniActivity_cppOcctMicroVersion (JNIEnv* theEnv,
831                                                                                        jobject theObj)
832 {
833   return OCC_VERSION_MAINTENANCE;
834 }