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