0031851: Data Exchange, STEP - enable Unicode symbols in STEP export
[occt.git] / samples / qt / AndroidQt / src / AndroidQt.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 #if defined(_WIN32)
15   #include <windows.h>
16 #endif
17
18 #include "AndroidQt.h"
19 #include "AndroidQt_UserInteractionParameters.h"
20 #include "AndroidQt_Window.h"
21
22 #include <AIS_Shape.hxx>
23 #include <BRepTools.hxx>
24 #include <BRep_Builder.hxx>
25 #include <Message.hxx>
26 #include <Message_Messenger.hxx>
27 #include <OpenGl_GraphicDriver.hxx>
28 #include <Quantity_Color.hxx>
29 #include <Standard_ErrorHandler.hxx>
30 #include <TopoDS.hxx>
31 #include <TopoDS_Face.hxx>
32 #include <TopoDS_Shape.hxx>
33 #include <UnitsAPI.hxx>
34 #include <WNT_Window.hxx>
35
36 #include <EGL/egl.h>
37
38 #include <Standard_WarningsDisable.hxx>
39 #include <QFileInfo>
40 #include <Standard_WarningsRestore.hxx>
41
42 // =======================================================================
43 // function : AndroidQt
44 // purpose  :
45 // =======================================================================
46 AndroidQt::AndroidQt()
47 : myFitAllAction (false)
48 {
49   connect (this, SIGNAL (windowChanged (QQuickWindow*)), this, SLOT (handleWindowChanged (QQuickWindow*)));
50
51   // set shaders location variable
52   QByteArray aDataRoot = "/data/data/org.qtproject.example.AndroidQt/files/opencascade/shared";
53   qputenv ("CSF_ShadersDirectory", aDataRoot + "/Shaders");
54 }
55
56 // =======================================================================
57 // function : ReadShapeFromFile
58 // purpose  :
59 // =======================================================================
60 bool AndroidQt::ReadShapeFromFile (QString theFilePath)
61 {
62   QUrl    aFileUrl   (theFilePath);
63   QString aFilePath = theFilePath;
64   if (aFileUrl.isLocalFile())
65   {
66     aFilePath = QUrl (theFilePath).toLocalFile();
67   }
68
69   if (!QFile (aFilePath).exists())
70   {
71     return false;
72   }
73
74   TopoDS_Shape aShape;
75   BRep_Builder aBuildTool;
76   try
77   {
78     OCC_CATCH_SIGNALS
79
80     if (!BRepTools::Read (aShape, aFilePath.toStdString().c_str(), aBuildTool))
81     {
82       return false;
83     }
84
85     if (!myContext.IsNull())
86     {
87       myContext->EraseAll (Standard_False);
88
89       Handle(AIS_Shape) aShapePrs = new AIS_Shape (aShape);
90       aShapePrs->SetColor (Quantity_Color(1.0, 0.73, 0.2, Quantity_TOC_RGB));
91
92       myContext->Display        (aShapePrs, Standard_False);
93       myContext->SetDisplayMode (aShapePrs, AIS_Shaded, Standard_False);
94     }
95
96     myMutex.lock();
97     myFitAllAction = true;
98     myMutex.unlock();
99
100     if (window())
101     {
102       window()->update();
103     }
104   }
105   catch (Standard_Failure)
106   {
107     return false;
108   }
109
110   return true;
111 }
112
113 // =======================================================================
114 // function : InitTouch
115 // purpose  :
116 // =======================================================================
117 void AndroidQt::InitTouch (const double theX,
118                            const double theY)
119 {
120   myMutex.lock();
121   myTouchPoint.SetStarts (theX, theY);
122   myMutex.unlock();
123 }
124
125 // =======================================================================
126 // function : UpdateTouch
127 // purpose  :
128 // =======================================================================
129 void AndroidQt::UpdateTouch (const double theX,
130                              const double theY)
131 {
132   myMutex.lock();
133   myTouchPoint.SetEnds (theX, theY);
134   myMutex.unlock();
135
136   if (window())
137     window()->update();
138 }
139
140 // =======================================================================
141 // function : handleWindowChanged
142 // purpose  :
143 // =======================================================================
144 void AndroidQt::handleWindowChanged (QQuickWindow* theWin)
145 {
146   if (theWin == NULL)
147   {
148     return;
149   }
150
151   connect (theWin, SIGNAL (beforeSynchronizing()), this, SLOT (sync()), Qt::DirectConnection);
152
153   theWin->setClearBeforeRendering (false);
154 }
155
156 // =======================================================================
157 // function : sync
158 // purpose  :
159 // =======================================================================
160 void AndroidQt::sync()
161 {
162   myViewportSize = window()->size() * window()->devicePixelRatio();
163
164   Graphic3d_Vec2i aWinTopLeft (window()->x(), window()->y());
165   Graphic3d_Vec2i aWinSize (myViewportSize.width(), myViewportSize.height());
166   const bool isChangedLeft = (myWinTopLeft.x() != aWinTopLeft.x());
167   const bool isChangedTop = (myWinTopLeft.y() != aWinTopLeft.y());
168   myWinTopLeft = aWinTopLeft;
169
170   if (myViewer.IsNull())
171   {
172     initViewer (Aspect_Drawable (window()->winId()));
173     connect (window(), SIGNAL (beforeRendering()), this, SLOT (paint()), Qt::DirectConnection);
174   }
175   else
176   {
177     Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
178   #ifdef __ANDROID__
179     if (aDriver->getRawGlContext() != eglGetCurrentContext())
180     {
181       initViewer (Aspect_Drawable (window()->winId()));
182     }
183     else
184   #endif
185     {
186     #ifdef __ANDROID__
187       Handle(AndroidQt_Window) aWindow = Handle(AndroidQt_Window)::DownCast(myView->Window());
188       aWindow->SetSize (myViewportSize.width(), myViewportSize.height());
189       //myView->MustBeResized(); // can be used instead of SetWindow() when EGLsurface has not been changed
190
191       EGLContext anEglContext = eglGetCurrentContext();
192       myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
193     #else
194       if (aWinSize.x() != myWinSize.x()
195        || aWinSize.y() != myWinSize.y())
196       {
197         myView->MustBeResized();
198         myView->Invalidate();
199       }
200       else if (isChangedTop)
201       {
202         myView->MustBeResized();
203       }
204       else if (isChangedLeft)
205       {
206         myView->MustBeResized();
207       }
208     #endif
209     }
210   }
211   myWinSize = aWinSize;
212 }
213
214 // =======================================================================
215 // function : paint
216 // purpose  :
217 // =======================================================================
218 void AndroidQt::paint()
219 {
220   myMutex.lock();
221
222   if (Abs (myTouchPoint.DevX()) + Abs (myTouchPoint.DevY()) > 1)
223   {
224     myView->StartRotation ((Standard_Integer)myTouchPoint.X().first,  (Standard_Integer)myTouchPoint.Y().first);
225     myView->Rotation      ((Standard_Integer)myTouchPoint.X().second, (Standard_Integer)myTouchPoint.Y().second);
226
227     myTouchPoint.ClearDev();
228   }
229
230   if (myFitAllAction)
231   {
232     myView->FitAll();
233     myFitAllAction = false;
234   }
235
236   myMutex.unlock();
237
238   myView->Redraw();
239 }
240
241 // =======================================================================
242 // function : initViewer
243 // purpose  :
244 // =======================================================================
245 bool AndroidQt::initViewer (Aspect_Drawable theWin)
246 {
247   int aWidth = 0, aHeight = 0;
248   Handle(Aspect_DisplayConnection) aDisplayConnection;
249 #ifdef __ANDROID__
250   EGLint aCfgId = 0;
251   EGLDisplay anEglDisplay = eglGetCurrentDisplay();
252   EGLContext anEglContext = eglGetCurrentContext();
253   EGLSurface anEglSurf    = eglGetCurrentSurface (EGL_DRAW);
254
255   if (anEglDisplay == EGL_NO_DISPLAY
256    || anEglContext == EGL_NO_CONTEXT
257    || anEglSurf    == EGL_NO_SURFACE)
258   {
259     release();
260     return false;
261   }
262
263   eglQuerySurface (anEglDisplay, anEglSurf, EGL_WIDTH,     &aWidth);
264   eglQuerySurface (anEglDisplay, anEglSurf, EGL_HEIGHT,    &aHeight);
265   eglQuerySurface (anEglDisplay, anEglSurf, EGL_CONFIG_ID, &aCfgId);
266
267   const EGLint aConfigAttribs[] = { EGL_CONFIG_ID, aCfgId, EGL_NONE };
268   EGLint       aNbConfigs = 0;
269   void*        anEglConfig = NULL;
270
271   if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) != EGL_TRUE)
272   {
273     Message::DefaultMessenger()->Send ("Error: EGL does not provide compatible configurations", Message_Fail);
274     release();
275     return false;
276   }
277
278   if (!myViewer.IsNull())
279   {
280     Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (myViewer->Driver());
281     Handle(AndroidQt_Window)     aWindow = Handle(AndroidQt_Window)::DownCast (myView->Window());
282     if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig))
283     {
284       Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized", Message_Fail);
285       release();
286       return false;
287     }
288
289     aWindow->SetSize (aWidth, aHeight);
290     myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
291   }
292
293   Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (NULL, Standard_False);
294 #elif defined(_WIN32)
295   HWND  aWinHandle = (HWND)theWin;
296   HDC   aWindowDC = wglGetCurrentDC();
297   HGLRC aRendCtx   = wglGetCurrentContext();
298   if (aWinHandle == NULL
299    || aWindowDC  == NULL
300    || aRendCtx   == NULL)
301   {
302     Message::DefaultMessenger()->Send ("Error: No active WGL context!", Message_Fail);
303     release();
304     return false;
305   }
306
307   RECT aRect;
308   ::GetClientRect (aWinHandle, &aRect);
309   aWidth  = aRect.right - aRect.left;
310   aHeight = aRect.bottom - aRect.top;
311   myWinSize.x() = aWidth;
312   myWinSize.y() = aHeight;
313   if (!myViewer.IsNull())
314   {
315     Handle(WNT_Window) aWindow = new WNT_Window (aWinHandle);
316     myView->SetWindow (aWindow, (Aspect_RenderingContext)aRendCtx);
317     return true;
318   }
319   Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisplayConnection, Standard_False);
320 #endif
321
322   aDriver->ChangeOptions().buffersNoSwap = Standard_True;
323   //aDriver->ChangeOptions().glslWarnings  = Standard_True; // for GLSL shaders debug
324
325 #ifdef __ANDROID__
326   if (!aDriver->InitEglContext (anEglDisplay, anEglContext, anEglConfig))
327   {
328     Message::DefaultMessenger()->Send ("Error: OpenGl_GraphicDriver can not be initialized", Message_Fail);
329     release();
330     return false;
331   }
332 #endif
333
334   // create viewer
335   myViewer = new V3d_Viewer (aDriver);
336   myViewer->SetDefaultBackgroundColor (AndroidQt_UserInteractionParameters::BgColor.Name());
337   myViewer->SetDefaultLights();
338   myViewer->SetLightOn();
339
340   // create AIS context
341   myContext = new AIS_InteractiveContext (myViewer);
342   myContext->SetDisplayMode (AIS_Shaded, false);
343
344 #ifdef __ANDROID__
345   Handle(AndroidQt_Window) aWindow = new AndroidQt_Window (aWidth, aHeight);
346 #elif defined(_WIN32)
347   Handle(WNT_Window)       aWindow = new WNT_Window (aWinHandle);
348 #endif
349
350   myView = myViewer->CreateView();
351   myView->SetImmediateUpdate (Standard_False);
352
353 #ifdef __ANDROID__
354   myView->SetWindow (aWindow, (Aspect_RenderingContext )anEglContext);
355 #else
356   myView->SetWindow (aWindow, (Aspect_RenderingContext )aRendCtx);
357 #endif
358   myView->TriedronDisplay (Aspect_TOTP_RIGHT_LOWER, Quantity_NOC_WHITE, 0.08, V3d_ZBUFFER);
359
360   return true;
361 }
362
363 // =======================================================================
364 // function : release
365 // purpose  :
366 // =======================================================================
367 void AndroidQt::release()
368 {
369   myContext.Nullify();
370   myView.Nullify();
371   myViewer.Nullify();
372 }