Project

General

Profile

Download (22.1 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / main / RubikSurfaceView.java @ 8d50e08d

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.main;
21

    
22
import android.app.ActivityManager;
23
import android.content.Context;
24
import android.content.pm.ConfigurationInfo;
25
import android.opengl.GLSurfaceView;
26
import android.util.AttributeSet;
27
import android.util.DisplayMetrics;
28
import android.view.MotionEvent;
29

    
30
import org.distorted.library.type.Static2D;
31
import org.distorted.library.type.Static3D;
32
import org.distorted.library.type.Static4D;
33
import org.distorted.objects.RubikObject;
34
import org.distorted.objects.RubikObjectMovement;
35
import org.distorted.solvers.SolverMain;
36
import org.distorted.states.RubikState;
37
import org.distorted.states.RubikStateSolver;
38
import org.distorted.states.RubikStateSolving;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

    
42
public class RubikSurfaceView extends GLSurfaceView
43
{
44
    private static final int NUM_SPEED_PROBES = 10;
45
    private static final int INVALID_POINTER_ID = -1;
46

    
47
    public static final int MODE_ROTATE  = 0;
48
    public static final int MODE_DRAG    = 1;
49
    public static final int MODE_REPLACE = 2;
50

    
51
    // Moving the finger from the middle of the vertical screen to the right edge will rotate a
52
    // given face by SWIPING_SENSITIVITY/2 degrees.
53
    private final static int SWIPING_SENSITIVITY  = 240;
54
    // Moving the finger by 0.33 of an inch will start a Rotation.
55
    private final static float ROTATION_SENSITIVITY =  0.33f;
56
    // Every 0.33 of an inch the direction of cube drag will reset.
57
    private final static float DIRECTION_SENSITIVITY=  0.33f;
58

    
59
    // Where did we get this sqrt(3)/2 ? From the (default, i.e. 60 degrees - see InternalOutputSurface!)
60
    // FOV of the projection matrix of the Node onto the Screen.
61
    // Take a look how the CAMERA_POINT is used in onTouchEvent - (x,y) there are expressed in sort of
62
    // 'half-NDC' coordinates i.e. they range from +0.5 to -0.5; thus CAMERA_POINT also needs to be
63
    // in 'half-NDC'. Since in this coordinate system the height of the screen is equal to 1, then the
64
    // Z-distance from the center of the object to the camera is equal to (scrHeight/2)/tan(FOV/2) =
65
    // 0.5/tan(30) = sqrt(3)/2.
66
    // Why is the Z-distance between the camera and the object equal to (scrHeight/2)/tan(FOV/2)?
67
    // Because of the way the View part of the ModelView matrix is constructed in EffectQueueMatrix.send().
68
    private final Static4D CAMERA_POINT = new Static4D(0, 0, (float)Math.sqrt(3)*0.5f, 0);
69

    
70
    private RubikRenderer mRenderer;
71
    private RubikPreRender mPreRender;
72
    private RubikObjectMovement mMovement;
73
    private boolean mDragging, mBeginningRotation, mContinuingRotation;
74
    private int mScreenWidth, mScreenHeight, mScreenMin;
75

    
76
    private int mPtrID1, mPtrID2;
77
    private float mX, mY, mBegX1, mBegY1, mBegX2, mBegY2;
78
    private float mStartRotX, mStartRotY;
79
    private float mAxisX, mAxisY;
80
    private float mRotationFactor;
81
    private int mLastCubitColor, mLastCubitFace, mLastCubit;
82
    private int mCurrentAxis, mCurrentRow;
83
    private float mCurrentAngle, mCurrRotSpeed;
84
    private float[] mLastX;
85
    private float[] mLastY;
86
    private long[] mLastT;
87
    private int mFirstIndex, mLastIndex;
88
    private int mDensity;
89

    
90
    private static Static4D mQuatCurrent    = new Static4D(0,0,0,1);
91
    private static Static4D mQuatAccumulated= new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
92
    private static Static4D mTempCurrent    = new Static4D(0,0,0,1);
93
    private static Static4D mTempAccumulated= new Static4D(0,0,0,1);
94

    
95
///////////////////////////////////////////////////////////////////////////////////////////////////
96

    
97
    void setScreenSize(int width, int height)
98
      {
99
      mScreenWidth = width;
100
      mScreenHeight= height;
101

    
102
      mScreenMin = Math.min(width, height);
103
      }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106

    
107
    boolean isVertical()
108
      {
109
      return mScreenHeight>mScreenWidth;
110
      }
111

    
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

    
114
    RubikRenderer getRenderer()
115
      {
116
      return mRenderer;
117
      }
118

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

    
121
    RubikPreRender getPreRender()
122
      {
123
      return mPreRender;
124
      }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127

    
128
    void setQuatAccumulated()
129
      {
130
      mQuatAccumulated.set(mTempAccumulated);
131
      }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
    void setQuatCurrent()
136
      {
137
      mQuatCurrent.set(mTempCurrent);
138
      }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
    Static4D getQuatAccumulated()
143
      {
144
      return mQuatAccumulated;
145
      }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
    Static4D getQuatCurrent()
150
      {
151
      return mQuatCurrent;
152
      }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
    void setMovement(RubikObjectMovement movement)
157
      {
158
      mMovement = movement;
159
      }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
    private Static4D quatFromAngle(float angle)
164
      {
165
      float cosA = (float)Math.cos(angle);
166
      float sinA =-(float)Math.sin(angle);
167

    
168
      return new Static4D(0, 0, sinA, cosA);
169
      }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172

    
173
    private Static4D quatFromDrag(float dragX, float dragY)
174
      {
175
      float axisX = dragY;  // inverted X and Y - rotation axis is perpendicular to (dragX,dragY)
176
      float axisY = dragX;  // Why not (-dragY, dragX) ? because Y axis is also inverted!
177
      float axisZ = 0;
178
      float axisL = (float)Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
179

    
180
      if( axisL>0 )
181
        {
182
        axisX /= axisL;
183
        axisY /= axisL;
184
        axisZ /= axisL;
185

    
186
        float ratio = axisL;
187
        ratio = ratio - (int)ratio;     // the cos() is only valid in (0,Pi)
188

    
189
        float cosA = (float)Math.cos(Math.PI*ratio);
190
        float sinA = (float)Math.sqrt(1-cosA*cosA);
191

    
192
        return new Static4D(axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
193
        }
194

    
195
      return new Static4D(0f, 0f, 0f, 1f);
196
      }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199
// cast the 3D axis we are currently rotating along to the 2D in-screen-surface axis
200

    
201
    private void computeCurrentAxis(Static3D axis)
202
      {
203
      Static4D axis4D = new Static4D(axis.get0(), axis.get1(), axis.get2(), 0);
204
      Static4D result = rotateVectorByQuat(axis4D, mQuatAccumulated);
205

    
206
      mAxisX =result.get0();
207
      mAxisY =result.get1();
208

    
209
      float len = (float)Math.sqrt(mAxisX*mAxisX + mAxisY*mAxisY);
210
      mAxisX /= len;
211
      mAxisY /= len;
212
      }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
    private float continueRotation(float dx, float dy)
217
      {
218
      float alpha = dx*mAxisX + dy*mAxisY;
219
      float x = dx - alpha*mAxisX;
220
      float y = dy - alpha*mAxisY;
221

    
222
      float len = (float)Math.sqrt(x*x + y*y);
223

    
224
      // we have the length of 1D vector 'angle', now the direction:
225
      float tmp = mAxisY==0 ? -mAxisX*y : mAxisY*x;
226

    
227
      return (tmp>0 ? 1:-1)*len*mRotationFactor;
228
      }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231
// return quat1*quat2
232

    
233
    public static Static4D quatMultiply( Static4D quat1, Static4D quat2 )
234
      {
235
      float qx = quat1.get0();
236
      float qy = quat1.get1();
237
      float qz = quat1.get2();
238
      float qw = quat1.get3();
239

    
240
      float rx = quat2.get0();
241
      float ry = quat2.get1();
242
      float rz = quat2.get2();
243
      float rw = quat2.get3();
244

    
245
      float tx = rw*qx - rz*qy + ry*qz + rx*qw;
246
      float ty = rw*qy + rz*qx + ry*qw - rx*qz;
247
      float tz = rw*qz + rz*qw - ry*qx + rx*qy;
248
      float tw = rw*qw - rz*qz - ry*qy - rx*qx;
249

    
250
      return new Static4D(tx,ty,tz,tw);
251
      }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254
// rotate 'vector' by quat  ( i.e. return quat*vector*(quat^-1) )
255

    
256
    public static Static4D rotateVectorByQuat(Static4D vector, Static4D quat)
257
      {
258
      float qx = quat.get0();
259
      float qy = quat.get1();
260
      float qz = quat.get2();
261
      float qw = quat.get3();
262

    
263
      Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw);
264
      Static4D tmp = quatMultiply(quat,vector);
265

    
266
      return quatMultiply(tmp,quatInverted);
267
      }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270
// rotate 'vector' by quat^(-1)  ( i.e. return (quat^-1)*vector*quat )
271

    
272
    public static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat)
273
      {
274
      float qx = quat.get0();
275
      float qy = quat.get1();
276
      float qz = quat.get2();
277
      float qw = quat.get3();
278

    
279
      Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw);
280
      Static4D tmp = quatMultiply(quatInverted,vector);
281

    
282
      return quatMultiply(tmp,quat);
283
      }
284

    
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286

    
287
    private void addSpeedProbe(float x, float y)
288
      {
289
      long currTime = System.currentTimeMillis();
290
      boolean theSame = mLastIndex==mFirstIndex;
291

    
292
      mLastIndex++;
293
      if( mLastIndex>=NUM_SPEED_PROBES ) mLastIndex=0;
294

    
295
      mLastT[mLastIndex] = currTime;
296
      mLastX[mLastIndex] = x;
297
      mLastY[mLastIndex] = y;
298

    
299
      if( mLastIndex==mFirstIndex)
300
        {
301
        mFirstIndex++;
302
        if( mFirstIndex>=NUM_SPEED_PROBES ) mFirstIndex=0;
303
        }
304

    
305
      if( theSame )
306
        {
307
        mLastT[mFirstIndex] = currTime;
308
        mLastX[mFirstIndex] = x;
309
        mLastY[mFirstIndex] = y;
310
        }
311
      }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314

    
315
    private void computeCurrentSpeedInInchesPerSecond()
316
      {
317
      long firstTime = mLastT[mFirstIndex];
318
      long lastTime  = mLastT[mLastIndex];
319
      float fX = mLastX[mFirstIndex];
320
      float fY = mLastY[mFirstIndex];
321
      float lX = mLastX[mLastIndex];
322
      float lY = mLastY[mLastIndex];
323

    
324
      long timeDiff = lastTime-firstTime;
325

    
326
      mLastIndex = 0;
327
      mFirstIndex= 0;
328

    
329
      mCurrRotSpeed = timeDiff>0 ? 1000*retFingerDragDistanceInInches(fX,fY,lX,lY)/timeDiff : 0;
330
      }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333

    
334
    private float retFingerDragDistanceInInches(float xFrom, float yFrom, float xTo, float yTo)
335
      {
336
      float xDist = mScreenWidth*(xFrom-xTo);
337
      float yDist = mScreenHeight*(yFrom-yTo);
338
      float distInPixels = (float)Math.sqrt(xDist*xDist + yDist*yDist);
339

    
340
      return distInPixels/mDensity;
341
      }
342

    
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344

    
345
    private void setUpDragOrRotate(boolean down, float x, float y)
346
      {
347
      int mode = RubikState.getMode();
348

    
349
      if( mode==MODE_DRAG )
350
        {
351
        mDragging           = true;
352
        mBeginningRotation  = false;
353
        mContinuingRotation = false;
354
        }
355
      else
356
        {
357
        Static4D touchPoint1 = new Static4D(x, y, 0, 0);
358
        Static4D rotatedTouchPoint1= rotateVectorByInvertedQuat(touchPoint1, mQuatAccumulated);
359
        Static4D rotatedCamera= rotateVectorByInvertedQuat(CAMERA_POINT, mQuatAccumulated);
360

    
361
        if( mMovement!=null && mMovement.faceTouched(rotatedTouchPoint1,rotatedCamera) )
362
          {
363
          mDragging           = false;
364
          mContinuingRotation = false;
365

    
366
          if( mode==MODE_ROTATE )
367
            {
368
            mBeginningRotation= mPreRender.canRotate();
369
            }
370
          else if( mode==MODE_REPLACE )
371
            {
372
            mBeginningRotation= false;
373

    
374
            if( down )
375
              {
376
              RubikStateSolver solver = (RubikStateSolver) RubikState.SVER.getStateClass();
377
              mLastCubitFace = mMovement.getTouchedFace();
378
              float[] point = mMovement.getTouchedPoint3D();
379
              int color = solver.getCurrentColor();
380
              RubikObject object = mPreRender.getObject();
381
              mLastCubit = object.getCubit(point);
382
              mPreRender.setTextureMap( mLastCubit, mLastCubitFace, color );
383
              mLastCubitColor = SolverMain.cubitIsLocked(object.getObjectList(), object.getSize(), mLastCubit);
384
              }
385
            }
386
          }
387
        else
388
          {
389
          mDragging           = true;
390
          mBeginningRotation  = false;
391
          mContinuingRotation = false;
392
          }
393
        }
394
      }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
    private void dragging(float x, float y)
399
      {
400
      mTempCurrent.set(quatFromDrag(mX-x,y-mY));
401
      mPreRender.setQuatCurrentOnNextRender();
402

    
403
      if( retFingerDragDistanceInInches(mX,mY,x,y) > DIRECTION_SENSITIVITY )
404
        {
405
        mX = x;
406
        mY = y;
407
        mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated));
408
        mTempCurrent.set(0f, 0f, 0f, 1f);
409
        mPreRender.setQuatCurrentOnNextRender();
410
        mPreRender.setQuatAccumulatedOnNextRender();
411
        }
412
      }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

    
416
    private void continuingRotation(float x, float y)
417
      {
418
      float angle = continueRotation(x-mStartRotX,y-mStartRotY);
419
      mCurrentAngle = SWIPING_SENSITIVITY*angle;
420
      mPreRender.getObject().continueRotation(mCurrentAngle);
421

    
422
      addSpeedProbe(x,y);
423
      }
424

    
425
///////////////////////////////////////////////////////////////////////////////////////////////////
426

    
427
    private void beginningRotation(float x, float y)
428
      {
429
      mStartRotX = x;
430
      mStartRotY = y;
431

    
432
      Static4D touchPoint2 = new Static4D(x, y, 0, 0);
433
      Static4D rotatedTouchPoint2= rotateVectorByInvertedQuat(touchPoint2, mQuatAccumulated);
434

    
435
      Static2D res = mMovement.newRotation(rotatedTouchPoint2);
436
      RubikObject object = mPreRender.getObject();
437

    
438
      mCurrentAxis = (int)res.get0();
439
      float offset = res.get1();
440
      mCurrentRow = (int)(object.returnMultiplier()*offset);
441
      computeCurrentAxis( object.getRotationAxis()[mCurrentAxis] );
442
      mRotationFactor = object.returnRotationFactor(offset);
443

    
444
      object.beginNewRotation( mCurrentAxis, mCurrentRow );
445

    
446
      if( RubikState.getCurrentState()==RubikState.READ )
447
        {
448
        RubikStateSolving solving = (RubikStateSolving)RubikState.SOLV.getStateClass();
449
        solving.resetElapsed();
450

    
451
        final RubikActivity act = (RubikActivity)getContext();
452

    
453
        act.runOnUiThread(new Runnable()
454
          {
455
          @Override
456
          public void run()
457
            {
458
            RubikState.switchState( act, RubikState.SOLV);
459
            }
460
          });
461
        }
462

    
463
      addSpeedProbe(x,y);
464

    
465
      mBeginningRotation = false;
466
      mContinuingRotation= true;
467
      }
468

    
469
///////////////////////////////////////////////////////////////////////////////////////////////////
470

    
471
    private void actionMove(MotionEvent event)
472
      {
473
      if( mPtrID2 == INVALID_POINTER_ID )
474
        {
475
        float x = (event.getX() - mScreenWidth*0.5f)/mScreenMin;
476
        float y = (mScreenHeight*0.5f -event.getY())/mScreenMin;
477

    
478
        if( mBeginningRotation )
479
          {
480
          if( retFingerDragDistanceInInches(mX,mY,x,y) > ROTATION_SENSITIVITY )
481
            {
482
            beginningRotation(x,y);
483
            }
484
          }
485
        else if( mContinuingRotation )
486
          {
487
          continuingRotation(x,y);
488
          }
489
        else if( mDragging )
490
          {
491
          dragging(x,y);
492
          }
493
        else
494
          {
495
          setUpDragOrRotate(false,x,y);
496
          }
497
        }
498
      else
499
        {
500
        int index1 = event.findPointerIndex(mPtrID1);
501
        int index2 = event.findPointerIndex(mPtrID2);
502

    
503
        float nX1 = event.getX(index1);
504
        float nY1 = event.getY(index1);
505
        float nX2 = event.getX(index2);
506
        float nY2 = event.getY(index2);
507

    
508
        float angle1 = (float) Math.atan2(mBegY1-mBegY2, mBegX1-mBegX2);
509
        float angle2 = (float) Math.atan2( nY1-nY2     , nX1-nX2      );
510

    
511
        mTempCurrent.set(quatFromAngle(angle1-angle2));
512
        mPreRender.setQuatCurrentOnNextRender();
513
        }
514
      }
515

    
516
///////////////////////////////////////////////////////////////////////////////////////////////////
517

    
518
    private void actionDown(MotionEvent event)
519
      {
520
      mPtrID1 = event.getPointerId(0);
521

    
522
      mX = (event.getX() - mScreenWidth*0.5f)/mScreenMin;
523
      mY = (mScreenHeight*0.5f -event.getY())/mScreenMin;
524

    
525
      setUpDragOrRotate(true,mX,mY);
526
      }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529

    
530
    private void actionUp()
531
      {
532
      mPtrID1 = INVALID_POINTER_ID;
533

    
534
      if( mDragging )
535
        {
536
        mTempAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated));
537
        mTempCurrent.set(0f, 0f, 0f, 1f);
538
        mPreRender.setQuatCurrentOnNextRender();
539
        mPreRender.setQuatAccumulatedOnNextRender();
540
        }
541

    
542
      if( mContinuingRotation )
543
        {
544
        computeCurrentSpeedInInchesPerSecond();
545
        int angle = mPreRender.getObject().computeNearestAngle(mCurrentAngle, mCurrRotSpeed);
546
        mPreRender.finishRotation(angle);
547

    
548
        if( RubikState.getCurrentState()==RubikState.SOLV && angle!=0 )
549
          {
550
          RubikStateSolving solving = (RubikStateSolving)RubikState.SOLV.getStateClass();
551
          solving.addMove(mCurrentAxis, mCurrentRow, angle);
552
          }
553
        }
554

    
555
      if( mLastCubitColor>=0 )
556
        {
557
        mPreRender.setTextureMap( mLastCubit, mLastCubitFace, mLastCubitColor );
558
        }
559
      }
560

    
561
///////////////////////////////////////////////////////////////////////////////////////////////////
562

    
563
    private void actionDown2(MotionEvent event)
564
      {
565
      mPtrID2 = event.getPointerId(event.getActionIndex());
566

    
567
      int index1 = event.findPointerIndex(mPtrID1);
568
      mBegX1 = event.getX(index1);
569
      mBegY1 = event.getY(index1);
570

    
571
      mX = (mBegX1 - mScreenWidth*0.5f)/mScreenMin;
572
      mY = (mScreenHeight*0.5f -mBegY1)/mScreenMin;
573

    
574
      int index2 = event.findPointerIndex(mPtrID2);
575
      mBegX2 = event.getX(index2);
576
      mBegY2 = event.getY(index2);
577
      }
578

    
579
///////////////////////////////////////////////////////////////////////////////////////////////////
580

    
581
    private void actionUp2()
582
      {
583
      mPtrID2 = INVALID_POINTER_ID;
584
      }
585

    
586
///////////////////////////////////////////////////////////////////////////////////////////////////
587
// PUBLIC API
588
///////////////////////////////////////////////////////////////////////////////////////////////////
589

    
590
    public RubikSurfaceView(Context context, AttributeSet attrs)
591
      {
592
      super(context,attrs);
593

    
594
      if(!isInEditMode())
595
        {
596
        mLastCubitColor = -1;
597
        mCurrRotSpeed   = 0.0f;
598

    
599
        mLastX = new float[NUM_SPEED_PROBES];
600
        mLastY = new float[NUM_SPEED_PROBES];
601
        mLastT = new long[NUM_SPEED_PROBES];
602
        mFirstIndex =0;
603
        mLastIndex  =0;
604

    
605
        mPtrID1 = INVALID_POINTER_ID;
606
        mPtrID2 = INVALID_POINTER_ID;
607

    
608
        mRenderer  = new RubikRenderer(this);
609
        mPreRender = new RubikPreRender(this);
610

    
611
        RubikActivity act = (RubikActivity)context;
612
        DisplayMetrics dm = new DisplayMetrics();
613
        act.getWindowManager().getDefaultDisplay().getMetrics(dm);
614

    
615
        mDensity = dm.densityDpi;
616

    
617
        final ActivityManager activityManager= (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
618

    
619
        if( activityManager!=null )
620
          {
621
          final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
622
          setEGLContextClientVersion( (configurationInfo.reqGlEsVersion>>16) >= 3 ? 3:2 );
623
          setRenderer(mRenderer);
624
          }
625
        }
626
      }
627

    
628
///////////////////////////////////////////////////////////////////////////////////////////////////
629

    
630
    @Override
631
    public boolean onTouchEvent(MotionEvent event)
632
      {
633
      int action = event.getActionMasked();
634

    
635
      switch(action)
636
         {
637
         case MotionEvent.ACTION_DOWN        : actionDown(event) ; break;
638
         case MotionEvent.ACTION_MOVE        : actionMove(event) ; break;
639
         case MotionEvent.ACTION_UP          : actionUp()        ; break;
640
         case MotionEvent.ACTION_POINTER_DOWN: actionDown2(event); break;
641
         case MotionEvent.ACTION_POINTER_UP  : actionUp2()       ; break;
642
         }
643

    
644
      return true;
645
      }
646
}
647

    
(4-4/4)