From bb6e768ac2663cc7603aadac42d22b64ebd45bc4 Mon Sep 17 00:00:00 2001
From: Maxime Graulich <maxime.graulich@gmail.com>
Date: Mon, 8 Jul 2013 08:37:46 +0000
Subject: [PATCH] Use Trackball for rotation, scale around the start point and
 translate on the current 2D plane

---
 contrib/mobile/Trackball.cpp     | 327 +++++++++++++++
 contrib/mobile/Trackball.h       |  79 ++++
 contrib/mobile/androidGModel.cpp |  36 +-
 contrib/mobile/androidGModel.h   |  25 +-
 contrib/mobile/drawContext.cpp   | 683 +++++++++++++++++++++++++++++++
 contrib/mobile/drawContext.h     |  65 +++
 contrib/mobile/movePosition.h    |  45 ++
 7 files changed, 1216 insertions(+), 44 deletions(-)
 create mode 100644 contrib/mobile/Trackball.cpp
 create mode 100644 contrib/mobile/Trackball.h
 create mode 100644 contrib/mobile/drawContext.cpp
 create mode 100644 contrib/mobile/drawContext.h
 create mode 100644 contrib/mobile/movePosition.h

diff --git a/contrib/mobile/Trackball.cpp b/contrib/mobile/Trackball.cpp
new file mode 100644
index 0000000000..3b01bdbafd
--- /dev/null
+++ b/contrib/mobile/Trackball.cpp
@@ -0,0 +1,327 @@
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * Trackball code:
+ *
+ * Implementation of a virtual trackball.
+ * Implemented by Gavin Bell, lots of ideas from Thant Tessman and
+ *   the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
+ *
+ * Vector manip code:
+ *
+ * Original code from:
+ * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
+ *
+ * Much mucking with by:
+ * Gavin Bell
+ */
+/*
+ * Modified for inclusion in Gmsh (rotmatrix as a vector +
+ * float->double + optional use of hyperbolic sheet for z-rotation)
+ */
+#include <math.h>
+#include "Trackball.h"
+#include <iostream>
+/*
+ * This size should really be based on the distance from the center of
+ * rotation to the point on the object underneath the mouse.  That
+ * point would then track the mouse as closely as possible.  This is a
+ * simple example, though, so that is left as an Exercise for the
+ * Programmer.
+ */
+#define TRACKBALLSIZE  (.8)
+
+/*
+ * Local function prototypes (not defined in trackball.h)
+ */
+static double tb_project_to_sphere(double, double, double);
+static void normalize_quat(double [4]);
+using namespace std ;
+
+void
+vzero(double *v)
+{
+    v[0] = 0.0;
+    v[1] = 0.0;
+    v[2] = 0.0;
+}
+
+void
+vset(double *v, double x, double y, double z)
+{
+    v[0] = x;
+    v[1] = y;
+    v[2] = z;
+}
+
+void
+vsub(const double *src1, const double *src2, double *dst)
+{
+    dst[0] = src1[0] - src2[0];
+    dst[1] = src1[1] - src2[1];
+    dst[2] = src1[2] - src2[2];
+}
+
+void
+vcopy(const double *v1, double *v2)
+{
+    register int i;
+    for (i = 0 ; i < 3 ; i++)
+        v2[i] = v1[i];
+}
+
+void
+vcross(const double *v1, const double *v2, double *cross)
+{
+    double temp[3];
+
+    temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
+    temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
+    temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
+    vcopy(temp, cross);
+}
+
+double
+vlength(const double *v)
+{
+    return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+}
+
+void
+vscale(double *v, double div)
+{
+    v[0] *= div;
+    v[1] *= div;
+    v[2] *= div;
+}
+
+void
+vnormal(double *v)
+{
+    vscale(v,1.0/vlength(v));
+}
+
+double
+vdot(const double *v1, const double *v2)
+{
+    return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+void
+vadd(const double *src1, const double *src2, double *dst)
+{
+    dst[0] = src1[0] + src2[0];
+    dst[1] = src1[1] + src2[1];
+    dst[2] = src1[2] + src2[2];
+}
+
+/*
+ * Ok, simulate a track-ball.  Project the points onto the virtual
+ * trackball, then figure out the axis of rotation, which is the cross
+ * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
+ * Note:  This is a deformed trackball-- is a trackball in the center,
+ * but is deformed into a hyperbolic sheet of rotation away from the
+ * center.  This particular function was chosen after trying out
+ * several variations.
+ *
+ * It is assumed that the arguments to this routine are in the range
+ * (-1.0 ... 1.0)
+ */
+void
+trackball(double q[4], double p1x, double p1y, double p2x, double p2y)
+{
+  double a[3]; /* Axis of rotation */
+  double phi;  /* how much to rotate about axis */
+  double p1[3], p2[3], d[3];
+  double t;
+
+  if (p1x == p2x && p1y == p2y) {
+    /* Zero rotation */
+    vzero(q);
+    q[3] = 1.0;
+    return;
+  }
+
+  /*
+   * First, figure out z-coordinates for projection of P1 and P2 to
+   * deformed sphere
+   */
+  vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
+  vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
+  /*
+   *  Now, we want the cross product of P1 and P2
+   */
+  vcross(p2,p1,a);
+   
+  /*
+   *  Figure out how much to rotate around that axis.
+   */
+  vsub(p1,p2,d);
+  t = vlength(d);
+    
+  /*
+   * Avoid problems with out-of-control values...
+   */
+  if (t > 1.0) t = 1.0;
+  if (t < -1.0) t = -1.0;
+  phi = 2.0 * asin(t);
+
+  axis_to_quat(a,phi,q);
+}
+
+/*
+ *  Given an axis and angle, compute quaternion.
+ */
+void axis_to_quat(double a[3], double phi, double q[4])
+{
+    vnormal(a);
+    vcopy(a,q);
+    vscale(q,sin(phi/2.0));
+    q[3] = cos(phi/2.0);
+}
+
+/*
+ * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
+ * if we are away from the center of the sphere.
+ */
+static double
+tb_project_to_sphere(double r, double x, double y)
+{
+  double d, t, z;
+
+  d = sqrt(x*x + y*y);
+
+  if (d < r ) {    
+    z = sqrt(r*r - d*d);
+  } else {           
+    z = 0.;
+  }
+
+  return z;
+}
+
+/*
+ * Given two rotations, e1 and e2, expressed as quaternion rotations,
+ * figure out the equivalent single rotation and stuff it into dest.
+ *
+ * This routine also normalizes the result every RENORMCOUNT times it is
+ * called, to keep error from creeping in.
+ *
+ * NOTE: This routine is written so that q1 or q2 may be the same
+ * as dest (or each other).
+ */
+
+#define RENORMCOUNT 97
+
+void
+add_quats(double q1[4], double q2[4], double dest[4])
+{
+    static int count=0;
+    double t1[4], t2[4], t3[4];
+    double tf[4];
+
+    vcopy(q1,t1);
+    vscale(t1,q2[3]);
+
+    vcopy(q2,t2);
+    vscale(t2,q1[3]);
+
+    vcross(q2,q1,t3);
+    vadd(t1,t2,tf);
+    vadd(t3,tf,tf);
+    tf[3] = q1[3] * q2[3] - vdot(q1,q2);
+
+    dest[0] = tf[0];
+    dest[1] = tf[1];
+    dest[2] = tf[2];
+    dest[3] = tf[3];
+
+    if (++count > RENORMCOUNT) {
+        count = 0;
+        normalize_quat(dest);
+    }
+}
+
+/*
+ * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
+ * If they don't add up to 1.0, dividing by their magnitued will
+ * renormalize them.
+ *
+ * Note: See the following for more information on quaternions:
+ *
+ * - Shoemake, K., Animating rotation with quaternion curves, Computer
+ *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
+ * - Pletinckx, D., Quaternion calculus as a basic tool in computer
+ *   graphics, The Visual Computer 5, 2-13, 1989.
+ */
+static void
+normalize_quat(double q[4])
+{
+    int i;
+    double mag;
+
+    mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+    for (i = 0; i < 4; i++) q[i] /= mag;
+}
+
+/*
+ * Build a rotation matrix, given a quaternion rotation.
+ *
+ */
+void
+build_rotmatrix(double m[16], double q[4])
+{
+    m[0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
+    m[1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
+    m[2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
+    m[3] = 0.0;
+
+    m[4] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
+    m[5]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
+    m[6] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
+    m[7] = 0.0;
+
+    m[8] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
+    m[9] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
+    m[10] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
+    m[11] = 0.0;
+
+    m[12] = 0.0;
+    m[13] = 0.0;
+    m[14] = 0.0;
+    m[15] = 1.0;
+}
diff --git a/contrib/mobile/Trackball.h b/contrib/mobile/Trackball.h
new file mode 100644
index 0000000000..6a46832022
--- /dev/null
+++ b/contrib/mobile/Trackball.h
@@ -0,0 +1,79 @@
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States.  Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * trackball.h
+ * A virtual trackball implementation
+ * Written by Gavin Bell for Silicon Graphics, November 1988.
+ */
+
+/*
+ * Pass the x and y coordinates of the last and current positions of
+ * the mouse, scaled so they are from (-1.0 ... 1.0).
+ *
+ * The resulting rotation is returned as a quaternion rotation in the
+ * first paramater.
+ */
+void
+trackball(double q[4], double p1x, double p1y, double p2x, double p2y);
+
+/*
+ * Given two quaternions, add them together to get a third quaternion.
+ * Adding quaternions to get a compound rotation is analagous to adding
+ * translations to get a compound translation.  When incrementally
+ * adding rotations, the first argument here should be the new
+ * rotation, the second and third the total rotation (which will be
+ * over-written with the resulting new total rotation).
+ */
+void
+add_quats(double *q1, double *q2, double *dest);
+
+/*
+ * A useful function, builds a rotation matrix in Matrix based on
+ * given quaternion.
+ */
+void
+build_rotmatrix(double m[16], double q[4]);
+
+/*
+ * This function computes a quaternion based on an axis (defined by
+ * the given vector) and an angle about which to rotate.  The angle is
+ * expressed in radians.  The result is put into the third argument.
+ */
+void
+axis_to_quat(double a[3], double phi, double q[4]);
+
+double trackballsize() ;
diff --git a/contrib/mobile/androidGModel.cpp b/contrib/mobile/androidGModel.cpp
index 9d6e0b499f..0827a1aa07 100644
--- a/contrib/mobile/androidGModel.cpp
+++ b/contrib/mobile/androidGModel.cpp
@@ -14,7 +14,7 @@
 #include <gmsh/PViewOptions.h>
 
 #include "androidGModel.h"
-#include "drawGModel.h"
+#include "drawContext.h"
 
 onelab::server *getOnelab() {return onelab::server::instance();}
 
@@ -32,6 +32,7 @@ class MobileMessage : public GmshMessage
 	{
 		if(level == "Error")
 		{
+	 		LOGE("%s", message.c_str());
 			if(message.size() <= 26 || message.substr(message.size()-25,25) != "check the log for details")
 				return;
 			if(!gCallbackObject)
@@ -48,15 +49,12 @@ class MobileMessage : public GmshMessage
 			env->CallVoidMethod(gCallbackObject, mid, jstr);
 			env->DeleteLocalRef(jstr);
 			env->DeleteLocalRef(jClass);
-	 		LOGE("%s", message.c_str());
 			return;
 		}
 		else if(level == "Progress")
 		{
 			if(!gCallbackObject)
 				return;
-			//if ((gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_6)) < 0) 
-			//	return;
 			if ((gJavaVM->AttachCurrentThread(&env, NULL)) < 0)
 				return;
 			jstring jstr = env->NewStringUTF(message.c_str());
@@ -76,7 +74,7 @@ class MobileMessage : public GmshMessage
 			requestRender();
 			return;
 		}
-	 	LOGI("%s", message.c_str());
+	 	LOGI("%s:\t%s", level.c_str(), message.c_str());
 	}
 };
 
@@ -109,47 +107,37 @@ JNIEXPORT jlong JNICALL Java_org_geuz_onelab_Gmsh_init
 	Msg::SetCallback(new MobileMessage());
 	
 	const char*  name = env->GetStringUTFChars(jname, NULL);
-	return reinterpret_cast<jlong>(new drawGModel());
+	return reinterpret_cast<jlong>(new drawContext());
 }
 JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_loadFile
   (JNIEnv *env, jobject obj, jlong jptr, jstring jname)
 {
 	const char*  filename = env->GetStringUTFChars(jname, NULL);
-	((drawGModel *)jptr)->load(filename);
+	((drawContext *)jptr)->load(filename);
 }
 JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_initView
   (JNIEnv *env, jobject obj, jlong jptr, jint w, jint h)
 {
-	((drawGModel *)jptr)->initView(w,h);
+	((drawContext *)jptr)->initView(w,h);
 }
 JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_drawView
   (JNIEnv *env, jobject obj, jlong jptr)
 {
-	((drawGModel *)jptr)->drawView();
-}
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setTranslation
-  (JNIEnv *env, jobject obj, jlong jptr, jfloat tx, jfloat ty, jfloat tz)
-{
-	((drawGModel *)jptr)->setTranslation(tx, ty, tz);
-}
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setScale
-  (JNIEnv *env, jobject obj, jlong jptr, jfloat sx, jfloat sy, jfloat sz)
-{
-	((drawGModel *)jptr)->setScale(sx, sy, sz);
+	((drawContext *)jptr)->drawView();
 }
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setRotate
-  (JNIEnv *env, jobject obj, jlong jptr, jfloat rx, jfloat ry, jfloat rz)
+JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_eventHandler
+  (JNIEnv *env, jobject obj, jlong jptr, jint jevent, jfloat jx, jfloat jy)
 {
-	((drawGModel *)jptr)->setRotation(rx, ry, rz);
+	((drawContext *)jptr)->eventHandler(jevent, jx, jy);
 }
 JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setShow
   (JNIEnv *env, jobject obj, jlong jptr, jstring jwhat, jboolean value)
 {
 	const char*  what = env->GetStringUTFChars(jwhat, NULL);
 	if(strcmp(what, "mesh") == 0)
-		((drawGModel *)jptr)->showMesh(value);
+		((drawContext *)jptr)->showMesh(value);
 	else if(strcmp(what, "geom") == 0)
-		((drawGModel *)jptr)->showGeom(value);
+		((drawContext *)jptr)->showGeom(value);
 }
 JNIEXPORT jlong JNICALL Java_org_geuz_onelab_Gmsh_getOnelabInstance
   (JNIEnv *env , jobject obj)
diff --git a/contrib/mobile/androidGModel.h b/contrib/mobile/androidGModel.h
index 9302ef6879..21192e45a3 100644
--- a/contrib/mobile/androidGModel.h
+++ b/contrib/mobile/androidGModel.h
@@ -5,6 +5,7 @@
 #ifndef _Included_org_geuz_onelab_Gmsh
 #define _Included_org_geuz_onelab_Gmsh
 void requestRender();
+unsigned char *getBitmapFromString(const char *text);
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -42,27 +43,11 @@ JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_drawView
 
 /*
  * Class:     org_geuz_onelab_Gmsh
- * Method:    setTranslation
- * Signature: (JFFF)V
+ * Method:    eventHandler
+ * Signature: (JIFF)V
  */
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setTranslation
-  (JNIEnv *, jobject, jlong, jfloat, jfloat, jfloat);
-
-/*
- * Class:     org_geuz_onelab_Gmsh
- * Method:    setScale
- * Signature: (JFFF)V
- */
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setScale
-  (JNIEnv *, jobject, jlong, jfloat, jfloat, jfloat);
-
-/*
- * Class:     org_geuz_onelab_Gmsh
- * Method:    setRotate
- * Signature: (JFFF)V
- */
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setRotate
-  (JNIEnv *, jobject, jlong, jfloat, jfloat, jfloat);
+JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_eventHandler
+  (JNIEnv *, jobject, jlong, jint, jfloat, jfloat);
 
 /*
  * Class:     org_geuz_onelab_Gmsh
diff --git a/contrib/mobile/drawContext.cpp b/contrib/mobile/drawContext.cpp
new file mode 100644
index 0000000000..ac6ff3ef50
--- /dev/null
+++ b/contrib/mobile/drawContext.cpp
@@ -0,0 +1,683 @@
+#if !defined(BUILD_ANDROID)
+#define BUILD_IOS 1
+#endif
+
+#include <map>
+
+#if defined(BUILD_IOS)
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
+
+#include <Gmsh/Gmsh.h>
+#include <Gmsh/GModel.h>
+#include <Gmsh/MElement.h>
+#include <Gmsh/VertexArray.h>
+#include <Gmsh/onelab.h>
+#include <Gmsh/onelabUtils.h>
+#include <Gmsh/PView.h>
+#include <Gmsh/PViewOptions.h>
+#include <Gmsh/Context.h>
+#include <Gmsh/StringUtils.h>
+
+#include <GetDP/GetDP.h>
+#endif
+
+#if defined(BUILD_ANDROID)
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <gmsh/Gmsh.h>
+#include <gmsh/GModel.h>
+#include <gmsh/MElement.h>
+#include <gmsh/VertexArray.h>
+#include <gmsh/onelab.h>
+#include <gmsh/onelabUtils.h>
+#include <gmsh/PView.h>
+#include <gmsh/PViewOptions.h>
+#include <gmsh/Context.h>
+#include <gmsh/StringUtils.h>
+
+#include <getdp/GetDP.h>
+
+#include "androidGModel.h"
+#endif
+
+#include "drawContext.h"
+#include "Trackball.h"
+
+static bool locked = false;
+
+drawContext::drawContext()
+{
+	new GModel();
+	GmshInitialize();
+	GmshSetOption("Mesh", "SurfaceFaces", 1.);
+	GmshSetOption("General", "Terminal", 1.);
+#ifdef DEBUG
+	GmshSetOption("General", "Verbosity", 99.);
+#else	
+	GmshSetOption("General", "Verbosity", 10.);
+#endif
+	onelabUtils::setFirstComputationFlag(false);
+	for(int i = 0; i < 3; i++){
+		_translate[i] = 0.;
+		_scale[i] = 1.;
+	}
+	setQuaternion(0., 0., 0., 1.);
+    
+	_fillMesh = false;
+	_showMesh = false;
+	_showGeom = true;
+	_gradiant = true;
+}
+
+static void checkGlError(const char* op) {
+	for (GLint error = glGetError(); error; error	= glGetError())
+		Msg::Error("%s: glError (0x%x)",op,error);
+}
+
+void drawContext::load(std::string filename)
+{
+	if(locked) return;
+	// clear previous GModel, onelab datas and PView
+	GModel::list.clear();
+	PView::list.clear();
+	onelab::server::instance()->clear();
+	
+	// open the file with Gmsh
+	GmshOpenProject(filename);
+    
+	// run getdp witout parameter
+	onelab_cb("check");
+    
+	// to allow the firs run
+	onelab::server::instance()->setChanged(true, "Gmsh");
+	onelab::server::instance()->setChanged(true, "GetDP");
+}
+
+void drawContext::eventHandler(int event, float x, float y)
+{
+	this->_current.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
+	switch(event)
+	{
+		case 0: // finger(s) press the screen
+			// in this case x and y represent the start point
+			this->_start.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
+			this->_previous.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
+			break;
+		case 1: // finger move (translate)
+			// in this case x and y represent the current point
+			_translate[0] += (this->_current.wnr[0] - this->_previous.wnr[0]);
+			_translate[1] += (this->_current.wnr[1] - this->_previous.wnr[1]);
+			_translate[2] = 0.;
+			break;
+		case 2: // fingers move (scale)
+			// in this case we don't care about previous and current position, x represent the scale
+			this->_scale[0] = this->_scale[1] = this->_scale[2] = x;
+			this->_start.recenter(this->_scale, this->_translate); // FIXME somethink change the value of win
+			break;
+		case 3: // fingers move (rotate)
+			this->addQuaternion((2. * this->_previous.win[0] - this->_width) / this->_width,
+                                (this->_height - 2. * this->_previous.win[1]) / this->_height,
+                                (2. * this->_current.win[0] - this->_width) / this->_width,
+                                (this->_height - 2. * this->_current.win[1]) / this->_height);
+			break;
+		case 4: // release the finger(s)
+			// Do nothink ?
+			break;
+		default: // all other reset the position
+			setQuaternion(0., 0., 0., 1.);
+			for(int i = 0; i < 3; i++){
+				_translate[i] = 0.;
+				_scale[i] = 1.;
+			}
+			break;
+	}
+	this->_previous.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
+}
+
+void drawContext::setQuaternion(double q0, double q1, double q2, double q3)
+{
+	this->_quaternion[0] = q0;
+	this->_quaternion[1] = q1;
+	this->_quaternion[2] = q2;
+	this->_quaternion[3] = q3;
+}
+
+void drawContext::addQuaternion(double p1x, double p1y, double p2x, double p2y)
+{
+  double quat[4];
+  trackball(quat, p1x, p1y, p2x, p2y);
+  add_quats(quat, this->_quaternion, this->_quaternion);
+}
+
+void drawContext::buildRotationMatrix()
+{
+	build_rotmatrix(_rotate, _quaternion);
+	for(int i=0; i<16;i++)
+		_rotatef[i] = (float)_rotate[i];
+}
+
+void drawContext::OrthofFromGModel()
+{
+	SBoundingBox3d bb = GModel::current()->bounds();
+	double ratio = (double)(this->_width ? this->_width : 1.) / (double)(this->_height ? this->_height : 1.);
+	double modelh = bb.max().y() - bb.min().y(), modelw = bb.max().x() - bb.min().x();
+	double modelratio = (modelw ? modelw : 1.) / (modelh ? modelh : 1.);
+	double xmin = -ratio, xmax = ratio, ymin = -1., ymax = 1.;
+	xmin = bb.min().x();
+	xmax = bb.max().x();
+	ymin = bb.min().x() / ratio;
+	ymax = bb.max().x() / ratio;
+	xmax += (xmax - xmin) / 5.;
+	xmin -= (xmax - xmin) / 5.;
+	ymax += (ymax - ymin) / 5.;
+	ymin -= (ymax - ymin) / 5.;
+	
+	// clipping
+	double zmax = std::max(fabs(bb.min().z()), fabs(bb.max().z()));
+	double clip = zmax  * 5.;
+	clip = 1.;
+
+	GLint matrixMode;
+	glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+	this->_left = (xmin != 0 || xmax != 0)? xmin : -ratio;
+	this->_right = (xmin != 0 || xmax != 0)? xmax : ratio;
+	this->_top = (xmin != 0 || xmax != 0)? ymax : 1.0;
+	this->_bottom = (xmin != 0 || xmax != 0)? ymin : -1.0;
+	glOrthof(this->_left, this->_right, this->_bottom, this->_top, -clip, clip);
+    
+	glMatrixMode(matrixMode);
+}
+void drawContext::initView(int w, int h)
+{
+	this->_height = h;
+	this->_width = w;
+	glViewport(0, 0, w, h);
+
+	this->OrthofFromGModel();
+    
+	glClearColor(.83,.85,.98,1.);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void drawArray(VertexArray *va, GLint type, bool colorArray=false)
+{
+	if(!va) return;
+	glEnable(GL_BLEND);
+	glEnable(GL_RESCALE_NORMAL);
+	glShadeModel(GL_SMOOTH);
+	glVertexPointer(3, GL_FLOAT, 0, va->getVertexArray());
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glNormalPointer(GL_BYTE, 0, va->getNormalArray());
+	glEnableClientState(GL_NORMAL_ARRAY);
+	if(colorArray)
+	{
+		glColorPointer(4, GL_UNSIGNED_BYTE, 0, va->getColorArray());
+		glEnableClientState(GL_COLOR_ARRAY);
+	}
+	glDrawArrays(type, 0, va->getNumVertices());
+	glDisable(GL_POLYGON_OFFSET_FILL);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_NORMAL_ARRAY);
+	glDisableClientState(GL_COLOR_ARRAY);
+	glDisable(GL_RESCALE_NORMAL);
+	glDisable(GL_BLEND);
+}
+
+void drawVector(double x, double y, double z, double dx, double dy, double dz)
+{
+	double l = sqrt(dx * dx + dy * dy + dz * dz), lt;
+	double n[3], t[3], u[3];
+    
+	if(l == 0.0) return;
+    
+	GLfloat line[] = {
+		(GLfloat)x, (GLfloat)y, (GLfloat)z,
+		(GLfloat)(x+dx), (GLfloat)(y+dy), (GLfloat)(z+dz),
+	};
+	glVertexPointer(3, GL_FLOAT, 0, line);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glDrawArrays(GL_LINES, 0, 2);
+	glDisableClientState(GL_VERTEX_ARRAY);
+    
+	n[0] = dx / l;
+	n[1] = dy / l;
+	n[2] = dz / l;
+    
+	if((fabs(n[0]) >= fabs(n[1]) && fabs(n[0]) >= fabs(n[2])) ||
+       (fabs(n[1]) >= fabs(n[0]) && fabs(n[1]) >= fabs(n[2]))) {
+		t[0] = n[1];
+		t[1] = -n[0];
+		t[2] = 0.;
+	}
+	else {
+		t[0] = 0.;
+		t[1] = n[2];
+		t[2] = -n[1];
+	}
+    
+	lt = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);
+	t[0] /= lt;
+	t[1] /= lt;
+	t[2] /= lt;
+    
+	u[0] = n[1] * t[2] - n[2] * t[1];
+	u[1] = n[2] * t[0] - n[0] * t[2];
+	u[2] = n[0] * t[1] - n[1] * t[0];
+    
+	lt = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
+	u[0] /= lt;
+	u[1] /= lt;
+	u[2] /= lt;
+    
+	double f1 = 0.75; // Stem lenght
+	double b = 0.1 * l;
+	
+	GLfloat arrow[] = {
+		(GLfloat)(x + dx), (GLfloat)(y + dy), (GLfloat)(z + dz),
+		(GLfloat)(x + f1 * dx + b * (t[0])), (GLfloat)(y + f1 * dy + b * (t[1])), (GLfloat)(z + f1 * dz + b * (t[2])),
+		(GLfloat)(x + f1 * dx + b * (-t[0])), (GLfloat)(y + f1 * dy + b * (-t[1])), (GLfloat)(z + f1 * dz + b * (-t[2])),
+        
+		(GLfloat)(x + dx), (GLfloat)(y + dy), (GLfloat)(z + dz),
+		(GLfloat)(x + f1 * dx + b * (-u[0])), (GLfloat)(y + f1 * dy + b * (-u[1])), (GLfloat)(z + f1 * dz + b * (-u[2])),
+		(GLfloat)(x + f1 * dx + b * (u[0])), (GLfloat)(y + f1 * dy + b * (u[1])), (GLfloat)(z + f1 * dz + b * (u[2])),
+	};
+	glVertexPointer(3, GL_FLOAT, 0, arrow);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnable(GL_LINE_SMOOTH);
+	glDrawArrays(GL_TRIANGLES, 0, 6);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisable(GL_LINE_SMOOTH);
+    
+}
+
+void drawContext::drawVectorArray(PViewOptions *opt, VertexArray *va)
+{
+	if(!va || va->getNumVerticesPerElement() != 2) return;
+    
+	for(int i = 0; i < va->getNumVertices(); i += 2){
+		float *s = va->getVertexArray(3 * i);
+		float *v = va->getVertexArray(3 * (i + 1));
+		double l = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+		double lmax = opt->tmpMax;
+		if((l && opt->vectorType) && lmax)
+		{
+			double scale = (opt->arrowSizeMax - opt->arrowSizeMin) / lmax;
+			if(opt->arrowSizeMin && l) scale += opt->arrowSizeMin / l;
+			double dx = scale * v[0];
+			double dy = scale * v[1];
+			double dz = scale * v[2];
+			GLubyte *color = (GLubyte *)va->getColorArray(4 * i);
+			glColor4ub(*(color), *(color+1), *(color+2), *(color+3));
+			if(fabs(dx) > 1. || fabs(dy) > 1. || fabs(dz) > 1.)
+			{
+				double d = (this->_right - this->_left) / this->_width / _scale[0];
+				dx *= d; dy *= d; dz *= d;
+				double x = s[0], y = s[1], z = s[2];
+				drawVector(x,y,z,dx,dy,dz);
+			}
+		}
+	}
+}
+
+void drawContext::drawPView(PView *p)
+{
+	PViewOptions *opt = p->getOptions();
+	PViewData *data = p->getData(true);
+	if(!opt->visible) return;
+    
+	glPointSize((GLfloat)opt->pointSize);
+	glLineWidth((GLfloat)opt->lineWidth);
+    
+	drawArray(p->va_points, GL_POINTS,true);
+	drawArray(p->va_lines, GL_LINES,true);
+	drawArray(p->va_triangles, GL_TRIANGLES,true);
+
+	glLineWidth(1);
+	glPointSize(1);
+    
+	drawVectorArray(p->getOptions(), p->va_vectors);
+}
+
+void drawContext::drawScale()
+{
+	glPushMatrix();
+	glLoadIdentity();
+	// Draw the scale bar
+	if(PView::list.size() < 1) return;
+	PView *p = PView::list[PView::list.size()-1];
+	PViewOptions *opt = p->getOptions();
+    
+	double width = 6*(this->_right -this->_left) / 10.;
+	double height = (this->_top - this->_bottom) / 20.;
+	double box = width / (opt->nbIso ? opt->nbIso : 1);
+	double xmin = this->_left + (this->_right - this->_left -width)/2.;
+	double ymin = this->_bottom + height;
+    
+    GLfloat *vertex = (GLfloat *)malloc(opt->nbIso*3*4*sizeof(GLfloat));
+    GLubyte *color = (GLubyte *)malloc(opt->nbIso*4*4*sizeof(GLubyte));
+	for(int i = 0; i < opt->nbIso; i++){
+		if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric)
+		{
+			unsigned int col = opt->getColor(i, opt->nbIso);
+			color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
+			color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
+			color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
+			color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
+			vertex[i*3*4+0] = xmin + i * box;
+			vertex[i*3*4+1] = ymin;
+			vertex[i*3*4+2] = 0.;
+			vertex[i*3*4+3] = xmin + i * box;
+			vertex[i*3*4+4] = ymin + height;
+			vertex[i*3*4+5] = 0.;
+			vertex[i*3*4+6] = xmin + (i + 1) * box;
+			vertex[i*3*4+7] = ymin;
+			vertex[i*3*4+8] = 0.;
+			vertex[i*3*4+9] = xmin + (i + 1) * box;
+			vertex[i*3*4+10] = ymin + height;
+			vertex[i*3*4+11] = 0.;
+		}
+		else if(opt->intervalsType == PViewOptions::Continuous)
+		{
+			double dv = (opt->tmpMax - opt->tmpMin) / (opt->nbIso ? opt->nbIso : 1);
+			double v1 = opt->tmpMin + i * dv;
+			unsigned int col1 = opt->getColor(v1, opt->tmpMin, opt->tmpMax, true);
+			color[i*4*4+0] = color[i*4*4+4] = (GLubyte)CTX::instance()->unpackRed(col1);
+			color[i*4*4+1] = color[i*4*4+5] = (GLubyte)CTX::instance()->unpackGreen(col1);
+			color[i*4*4+2] = color[i*4*4+6] = (GLubyte)CTX::instance()->unpackBlue(col1);
+			color[i*4*4+3] = color[i*4*4+7] = (GLubyte)CTX::instance()->unpackAlpha(col1);
+			vertex[i*3*4+0] = xmin + i * box;
+			vertex[i*3*4+1] = ymin;
+			vertex[i*3*4+2] = 0.;
+			vertex[i*3*4+3] = xmin + i * box;
+			vertex[i*3*4+4] = ymin + height;
+			vertex[i*3*4+5] = 0.;
+			double v2 = opt->tmpMin + (i + 1) * dv;
+            unsigned int col2 = opt->getColor(v2, opt->tmpMin, opt->tmpMax, true);
+			color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col2);
+			color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col2);
+			color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col2);
+			color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col2);
+			vertex[i*3*4+6] = xmin + (i + 1) * box;
+			vertex[i*3*4+7] = ymin;
+			vertex[i*3*4+8] = 0.;
+			vertex[i*3*4+9] = xmin + (i + 1) * box;
+			vertex[i*3*4+10] = ymin + height;
+			vertex[i*3*4+11] = 0.;
+		}
+		else
+		{
+			unsigned int col = opt->getColor(i, opt->nbIso);
+			color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
+			color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
+			color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
+			color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
+			vertex[i*3*4+0] = xmin + i * box;
+			vertex[i*3*4+1] = ymin;
+			vertex[i*3*4+2] = 0.;
+			vertex[i*3*4+3] = xmin + i * box;
+			vertex[i*3*4+4] = ymin + height;
+			vertex[i*3*4+5] = 0.;
+			vertex[i*3*4+6] = xmin + (i + 1) * box;
+			vertex[i*3*4+7] = ymin;
+			vertex[i*3*4+8] = 0.;
+			vertex[i*3*4+9] = xmin + (i + 1) * box;
+			vertex[i*3*4+10] = ymin + height;
+			vertex[i*3*4+11] = 0.;
+		}
+	}
+	
+	glVertexPointer(3, GL_FLOAT, 0, vertex);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glColorPointer(4, GL_UNSIGNED_BYTE, 0, color);
+	glEnableClientState(GL_COLOR_ARRAY);
+	if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric || opt->intervalsType == PViewOptions::Continuous)
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, opt->nbIso*4);
+	else
+		glDrawArrays(GL_LINES, 0, opt->nbIso*4);
+	glDisableClientState(GL_COLOR_ARRAY);
+	glDisableClientState(GL_VERTEX_ARRAY);
+	free(vertex);
+	free(color);
+	glPopMatrix();
+}
+
+void drawContext::drawMesh()
+{
+	GModel::current()->fillVertexArrays();
+	glColor4f(0,0,0,1.);
+	for(GModel::fiter it = GModel::current()->firstFace(); it != GModel::current()->lastFace(); it++){
+		if(_fillMesh) drawArray((*it)->va_triangles, GL_TRIANGLES);
+		else drawArray((*it)->va_lines, GL_LINES);
+	}
+}
+
+void drawContext::drawPost()
+{
+	if(PView::list.empty()) return ;
+    
+	for(unsigned int i = 0; i < PView::list.size(); i++){
+		PView::list[i]->fillVertexArrays();
+		drawPView(PView::list[i]);
+	}
+}
+
+void drawContext::drawGeom()
+{
+	glColor4f(0,0,1.,1.);
+	glLineWidth(3);
+	for(GModel::eiter it = GModel::current()->firstEdge(); it != GModel::current()->lastEdge(); it++){
+		GEdge *e = *it;
+		int N = e->minimumDrawSegments() + 1;
+		Range<double> t_bounds = e->parBounds(0);
+		double t_min = t_bounds.low();
+		double t_max = t_bounds.high();
+        
+		// Create a VA for this edge
+		GLfloat edge[N*3];
+        
+		for(unsigned int i=0; i < N; i++) {
+			double t = t_min + (double)i / (double)(N-1) * (t_max - t_min);
+			GPoint p = e->point(t);
+			edge[i*3] = p.x(); edge[i*3+1] = p.y(); edge[i*3+2] = p.z();
+		}
+		// Then print the VA
+		glVertexPointer(3, GL_FLOAT, 0, edge);
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glDrawArrays(GL_LINE_STRIP, 0, N);
+		glDisableClientState(GL_VERTEX_ARRAY);
+	}
+	glLineWidth(1);
+}
+
+void drawContext::drawAxes(double x0, double y0, double z0, double h)
+{
+	glLineWidth(5);
+	glPushMatrix();
+	glLoadIdentity();
+	glTranslatef(x0, y0, z0);
+	glMultMatrixf(_rotatef);
+	glTranslatef(-x0, -y0, -z0);
+    
+    const GLfloat axes[] = {
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)(x0+h), (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)(y0+h), (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
+		(GLfloat)x0, (GLfloat)y0, (GLfloat)(z0+h),
+	};
+    const GLubyte colors[] = {
+        255, 0, 0, 255,
+        255, 0, 0, 255,
+        0, 0, 255, 255,
+        0, 0, 255, 255,
+        0, 255, 0, 255,
+        0, 255, 0, 255,
+    };
+	glVertexPointer(3, GL_FLOAT, 0, axes);
+	glEnableClientState(GL_VERTEX_ARRAY);
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
+    glEnableClientState(GL_COLOR_ARRAY);
+	glDrawArrays(GL_LINES, 0, 6);
+	glDisableClientState(GL_VERTEX_ARRAY);
+    glDisableClientState(GL_COLOR_ARRAY);
+	glPopMatrix();
+	glLineWidth(1);
+}
+
+void drawContext::drawView()
+{
+	this->OrthofFromGModel();
+    
+	glMatrixMode(GL_MODELVIEW);
+	// fill the background
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	if(_gradiant)
+	{
+		glPushMatrix();
+		glLoadIdentity();
+		const GLfloat squareVertices[] = {
+			(GLfloat)this->_top,	(GLfloat)this->_left, -5.,
+			(GLfloat)this->_top,	(GLfloat)this->_right, -5.,
+			(GLfloat)this->_bottom,	(GLfloat)this->_left, -5.,
+			(GLfloat)this->_bottom,	(GLfloat)this->_right, -5.,
+		};
+		const GLubyte squareColors[] = {
+			255, 255, 255, 255,
+			255, 255, 255, 255,
+			190, 200, 255, 255,
+			190, 200, 255, 255,
+		};
+		glVertexPointer(3, GL_FLOAT, 0, squareVertices);
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
+		glEnableClientState(GL_COLOR_ARRAY);
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+		glDisableClientState(GL_COLOR_ARRAY);
+		glDisableClientState(GL_VERTEX_ARRAY);
+		glPopMatrix();
+	}
+	checkGlError("Draw background");
+	//
+	glLoadIdentity();
+	glScalef(_scale[0], _scale[1], _scale[2]);
+	glTranslatef(_translate[0], _translate[1], _translate[2]);
+	this->buildRotationMatrix();
+	glMultMatrixf(_rotatef);
+	//glTranslatef(this->_translate[0]/this->_height,this->_translate[1]/this->_width,0);
+	//glScalef(this->_scale[0], this->_scale[1], this->_scale[2]);
+	checkGlError("Initialize position");
+
+	//
+	this->drawAxes(this->_right - (this->_top - this->_bottom)/9.0, this->_bottom + (this->_top - this->_bottom)/9.0, 0, (this->_top - this->_bottom)/10.);
+	this->drawPost();
+	if(_showGeom) this->drawGeom();
+	if(_showMesh) this->drawMesh();
+	//this->drawScale();
+	checkGlError("Draw model,post-pro,...");
+}
+
+std::vector<std::string> commandToVector(const std::string cmd)
+{
+	std::vector<std::string> ret;
+	int pos=0, last=0;
+	while((pos = cmd.find("-", last+1)) != std::string::npos)
+	{
+		ret.push_back(cmd.substr(last,pos-1-last));
+		last = pos;
+	}
+	ret.push_back(cmd.substr(last,cmd.size()-1));
+	return ret;
+}
+
+int onelab_cb(std::string action)
+{
+	Msg::Debug("Ask onlab to %s", action.c_str());
+	if(action == "stop")
+	{
+		onelab::string o("GetDP/Action", "stop");
+		o.setVisible(false);
+		o.setNeverChanged(true);
+		onelab::server::instance()->set(o);
+		return 0;
+	}
+	if(locked) return -1;
+	locked = true;
+	int redraw = 0;
+	if(action == "reset")
+	{
+        onelab::server::instance()->clear();
+        onelabUtils::runGmshClient(action, true);
+		action = "check";
+	}
+    
+	Msg::ResetErrorCounter();
+    
+	if(action == "compute")
+	{
+		onelabUtils::initializeLoop("1");
+		onelabUtils::initializeLoop("2");
+		onelabUtils::initializeLoop("3");
+	}
+    
+	do
+	{
+		if(onelabUtils::runGmshClient(action, true))
+			redraw = 1;
+        
+		if(redraw == 0 && !onelab::server::instance()->getChanged("GetDP"))continue;
+        
+		std::vector<onelab::string> ps;
+		onelab::server::instance()->get(ps, "GetDP/1ModelName");
+		if(ps.empty()){
+			std::vector<std::string> split = SplitFileName(GModel::current()->getFileName());
+			std::string name(split[0] + split[1]);
+			onelab::string o("GetDP/1ModelName", name, "Model name");
+			o.setKind("file");
+			onelab::server::instance()->set(o);
+		}
+		onelab::string o("GetDP/Action", action);
+		o.setVisible(false);
+		o.setNeverChanged(true);
+		onelab::server::instance()->set(o);
+        
+		if(action == "compute" && (onelab::server::instance()->getChanged("Gmsh") || onelab::server::instance()->getChanged("GetDP")))
+		{
+			std::string filename = GModel::current()->getFileName();
+			std::vector<std::string> args;
+			args.push_back("getdp");
+			std::vector<onelab::string> onelabArgs;
+			onelab::server::instance()->get(onelabArgs, "GetDP/1ModelName");
+			args.push_back((onelabArgs.empty())? SplitFileName(filename)[0] + SplitFileName(filename)[1] : onelabArgs[0].getValue());
+			onelab::server::instance()->get(onelabArgs, "GetDP/9ComputeCommand");
+			std::vector<std::string> compute = commandToVector((onelabArgs.empty())? "" : onelabArgs[0].getValue().c_str());
+			args.insert( args.end(), compute.begin(), compute.end() );
+			args.push_back("-onelab");
+			args.push_back("GetDP");
+			GetDP(args, onelab::server::instance());
+		}
+		if(action == "check" && (onelab::server::instance()->getChanged("Gmsh") || onelab::server::instance()->getChanged("GetDP")))
+		{
+			std::string filename = GModel::current()->getFileName();
+			std::vector<std::string> args;
+			args.push_back("getdp");
+			std::vector<onelab::string> onelabArgs;
+			args.push_back(SplitFileName(filename)[0] + SplitFileName(filename)[1]);
+			onelab::server::instance()->get(onelabArgs, "GetDP/9CheckCommand");
+			args.push_back((onelabArgs.empty())? "" : onelabArgs[0].getValue());
+			args.push_back("-onelab");
+			args.push_back("GetDP");
+			GetDP(args, onelab::server::instance());
+		}
+	} while(action == "compute" && (onelabUtils::incrementLoop("3") || onelabUtils::incrementLoop("2") || onelabUtils::incrementLoop("1")));
+    
+	locked = false;
+    
+	return redraw;
+}
+
+// vim:set ts=2:
diff --git a/contrib/mobile/drawContext.h b/contrib/mobile/drawContext.h
new file mode 100644
index 0000000000..f89c1de5bc
--- /dev/null
+++ b/contrib/mobile/drawContext.h
@@ -0,0 +1,65 @@
+#ifndef _DRAW_GMODEL_H_
+#define _DRAW_GMODEL_H_
+
+#if !defined(BUILD_ANDROID)
+#define BUILD_IOS 1
+#endif
+
+#include <string>
+
+#if defined(BUILD_IOS)
+#include <Gmsh/PView.h>
+#include <Gmsh/PViewOptions.h>
+#include <Gmsh/Context.h>
+#endif
+
+#include "movePosition.h"
+
+int onelab_cb(const std::string);
+
+class drawContext{
+private:
+	float _translate[3], _scale[3]; // current translation and scale
+	double _rotate[16]; // current rotation matrix (double for Trackball)
+	float _rotatef[16]; // current rotation matrix (float for OpenGL ES)
+	double _quaternion[4]; // current quaternion used for rotation
+	movePosition _start, _previous, _current; // store informations about user interactions
+	int _width, _height; // size of OpenGL context in pixel
+	float _left, _right, _top, _bottom; // value of "border"
+	bool _gradiant, // show the background gradiant
+	_showGeom, // show the Geometry
+	_showMesh, // show the Mesh
+	_fillMesh; // fill the Mesh
+    
+	void OrthofFromGModel(void);
+	void drawPView(PView *p);
+	void drawVectorArray(PViewOptions *opt, VertexArray *va);
+    
+public:
+	drawContext();
+	~drawContext(){}
+	void load(std::string filename);
+	void eventHandler(int event, float x=0, float y=0);
+	void setQuaternion(double q0, double q1, double q2, double q3);
+	void addQuaternion(double p1x, double p1y, double p2x, double p2y);
+	void buildRotationMatrix();
+	void setTranslate(int i, float t) {if(i>=0 && i<3) this->_translate[i] = t;}
+	float getTranslate(int i) {if(i>=0 && i<3) return this->_translate[i]; return 0;}
+	void setScale(int i, float s) {if(i>=0 && i<3) this->_scale[i] = s;}
+	float getScale(int i) {if(i>=0 && i<3) return this->_scale[i]; return 0;}
+	void initView(int w, int h);
+	void drawView();
+	void drawAxes(double x0=0., double y0=0., double z0=0., double h=0.5);
+	void drawGeom();
+	void drawMesh();
+	void drawPost();
+	void drawScale();
+	void useGradiant(bool gradiant=true) {_gradiant = gradiant;}
+	void showGeom(bool show=true) {_showGeom = show;}
+	void showMesh(bool show=true) {_showMesh = show;}
+	void fillMesh(bool show=true) {_fillMesh = show;}
+    bool isShowedMesh(){return _showMesh;}
+    bool isShowedGeom(){return _showGeom;}
+};
+
+#endif
diff --git a/contrib/mobile/movePosition.h b/contrib/mobile/movePosition.h
new file mode 100644
index 0000000000..b8e62cc5d8
--- /dev/null
+++ b/contrib/mobile/movePosition.h
@@ -0,0 +1,45 @@
+class movePosition {
+ public:
+  float win[3]; // window coordinates
+  float wnr[3]; // world coordinates BEFORE rotation
+  float s[3]; // scaling state when the event was recorded
+  float t[3]; // translation state when the event was recorded
+  movePosition()
+  {
+    for(int i = 0; i < 3; i++)
+      win[i] = wnr[i] = s[i] = t[i] = 0.;
+  }
+  movePosition(const movePosition &instance)
+  {
+    for(int i = 0; i < 3; i++){
+      win[i] = instance.win[i];
+      wnr[i] = instance.wnr[i];
+      s[i] = instance.s[i];
+      t[i] = instance.t[i];
+    }
+  }
+  void set(float scale[3], float translate[3], float vxmax, float vxmin, float vymin, float vymax, int width, int height, int x, int y)
+  {
+    for(int i = 0; i < 3; i++){
+      s[i] = scale[i];
+      t[i] = translate[i];
+    }
+    win[0] = (float)x;
+    win[1] = (float)y;
+    win[2] = 0.;
+
+    wnr[0] =
+      (vxmin + win[0] / (float)width * (vxmax - vxmin)) / scale[0] - translate[0];
+    wnr[1] =
+      (vymax - win[1] / (float)height * (vymax - vymin)) / scale[1] - translate[1];
+    wnr[2] = 0.;
+  }
+  void recenter(float scale[3], float translate[3]) const
+  {
+    // compute the equivalent translation to apply *after* the scaling so that
+    // the scaling is done around the point which was clicked:
+    translate[0] = t[0] * (s[0] / scale[0]) - wnr[0] * (1. - (s[0] / scale[0]));
+    translate[1] = t[1] * (s[1] / scale[1]) - wnr[1] * (1. - (s[1] / scale[1]));
+  }
+};
+
-- 
GitLab