Project

General

Profile

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

magiccube / src / main / java / org / distorted / magic / RubikCube.java @ 42772cff

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted 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
// Distorted 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 Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.magic;
21

    
22
import android.graphics.Bitmap;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

    
26
import org.distorted.library.effect.Effect;
27
import org.distorted.library.effect.EffectType;
28
import org.distorted.library.effect.MatrixEffectMove;
29
import org.distorted.library.effect.MatrixEffectQuaternion;
30
import org.distorted.library.effect.MatrixEffectRotate;
31
import org.distorted.library.effect.MatrixEffectScale;
32
import org.distorted.library.effect.VertexEffectSink;
33
import org.distorted.library.effectqueue.EffectQueue;
34
import org.distorted.library.main.DistortedEffects;
35
import org.distorted.library.main.DistortedNode;
36
import org.distorted.library.main.DistortedTexture;
37
import org.distorted.library.mesh.MeshCubes;
38
import org.distorted.library.mesh.MeshFlat;
39
import org.distorted.library.message.EffectListener;
40
import org.distorted.library.type.Dynamic1D;
41
import org.distorted.library.type.Static1D;
42
import org.distorted.library.type.Static3D;
43
import org.distorted.library.type.Static4D;
44

    
45
///////////////////////////////////////////////////////////////////////////////////////////////////
46

    
47
public class RubikCube extends DistortedNode
48
{
49
    private static final int POST_ROTATION_MILLISEC = 500;
50
    private static final int TEXTURE_SIZE = 100;
51

    
52
    private static final Static3D VectX = new Static3D(1,0,0);
53
    private static final Static3D VectY = new Static3D(0,1,0);
54
    private static final Static3D VectZ = new Static3D(0,0,1);
55

    
56
    public static final int VECTX = 0;  //
57
    public static final int VECTY = 1;  // don't change this
58
    public static final int VECTZ = 2;  //
59

    
60
    private DistortedNode[][][] mNodes;
61
    private MeshCubes[][][] mCubes;
62
    private DistortedEffects[][][] mEffects;
63
    private Static4D[][][] mQuatScramble;
64
    private Static3D[][][] mRotationAxis;
65
    private Dynamic1D[][][] mRotationAngle;
66
    private Static3D[][][] mCurrentPosition;
67
    private MatrixEffectRotate[][][] mRotateEffect;
68
    private Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal;
69
    private Static3D mMove, mScale, mNodeMove, mNodeScale;
70
    private DistortedTexture mTexture;
71

    
72
    private int mRotAxis, mRotRow;
73
    private int mSize;
74

    
75
    private DistortedTexture mNodeTexture;
76

    
77
///////////////////////////////////////////////////////////////////////////////////////////////////
78

    
79
    RubikCube(int size, Static4D quatCur, Static4D quatAcc, DistortedTexture texture, MeshFlat mesh, DistortedEffects effects)
80
      {
81
      super(texture,effects,mesh);
82

    
83
      mNodeTexture = texture;
84

    
85
      mSize = size;
86

    
87
      mRotationAngleStatic = new Static1D(0);
88
      mRotationAngleMiddle = new Static1D(0);
89
      mRotationAngleFinal  = new Static1D(0);
90

    
91
      mMove     = new Static3D(0,0,0);
92
      mScale    = new Static3D(1,1,1);
93
      mNodeMove = new Static3D(0,0,0);
94
      mNodeScale= new Static3D(1,1,1);
95

    
96
      mRotAxis = VECTX;
97
      mTexture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
98

    
99
      mNodes          = new DistortedNode[mSize][mSize][mSize];
100
      mCubes          = new MeshCubes[mSize][mSize][mSize];
101
      mEffects        = new DistortedEffects[mSize][mSize][mSize];
102
      mQuatScramble   = new Static4D[mSize][mSize][mSize];
103
      mRotationAxis   = new Static3D[mSize][mSize][mSize];
104
      mRotationAngle  = new Dynamic1D[mSize][mSize][mSize];
105
      mCurrentPosition= new Static3D[mSize][mSize][mSize];
106
      mRotateEffect   = new MatrixEffectRotate[mSize][mSize][mSize];
107

    
108
      Static3D[][][] cubeVectors = new Static3D[mSize][mSize][mSize];
109

    
110
      Static3D sinkCenter = new Static3D(TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f);
111
      Static3D matrCenter = new Static3D(0,0,0);
112
      Static4D region = new Static4D(0,0,0, TEXTURE_SIZE*0.72f);
113

    
114
      VertexEffectSink        sinkEffect = new VertexEffectSink( new Static1D(getSinkStrength()), sinkCenter, region );
115
      MatrixEffectMove        moveEffect = new MatrixEffectMove(mMove);
116
      MatrixEffectScale      scaleEffect = new MatrixEffectScale(mScale);
117
      MatrixEffectQuaternion quatCEffect = new MatrixEffectQuaternion(quatCur, matrCenter);
118
      MatrixEffectQuaternion quatAEffect = new MatrixEffectQuaternion(quatAcc, matrCenter);
119

    
120
      MatrixEffectMove       nodeMoveEffect  = new MatrixEffectMove(mNodeMove);
121
      MatrixEffectScale      nodeScaleEffect = new MatrixEffectScale(mNodeScale);
122

    
123
      effects.apply(nodeScaleEffect);
124
      effects.apply(nodeMoveEffect);
125

    
126
      // 3x2 bitmap = 6 squares:
127
      //
128
      // RED     GREEN   BLUE
129
      // YELLOW  WHITE   BROWN
130

    
131
      final float ze = 0.0f;
132
      final float ot = 1.0f/3.0f;
133
      final float tt = 2.0f/3.0f;
134
      final float oh = 1.0f/2.0f;
135
      final float of = 1.0f/40.0f;
136

    
137
      final Static4D mapFront = new Static4D(ze,oh, ze+ot,oh+oh);
138
      final Static4D mapBack  = new Static4D(tt,ze, tt+ot,ze+oh);
139
      final Static4D mapLeft  = new Static4D(ot,ze, ot+ot,ze+oh);
140
      final Static4D mapRight = new Static4D(ze,ze, ze+ot,ze+oh);
141
      final Static4D mapTop   = new Static4D(tt,oh, tt+ot,oh+oh);
142
      final Static4D mapBottom= new Static4D(ot,oh, ot+ot,oh+oh);
143

    
144
      final Static4D mapBlack = new Static4D(ze,ze, ze+of,ze+of);
145

    
146
      Static4D tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom;
147
      float nc = 0.5f*mSize;
148
      int vertices = (int)(24.0f/mSize + 2.0f);
149

    
150
      for(int x = 0; x< mSize; x++)
151
        for(int y = 0; y< mSize; y++)
152
          for(int z = 0; z< mSize; z++)
153
            {
154
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 ) // only the external walls
155
              {
156
              tmpLeft  = (x==       0 ? mapLeft  :mapBlack);
157
              tmpRight = (x== mSize-1 ? mapRight :mapBlack);
158
              tmpFront = (z== mSize-1 ? mapFront :mapBlack);
159
              tmpBack  = (z==       0 ? mapBack  :mapBlack);
160
              tmpTop   = (y== mSize-1 ? mapTop   :mapBlack);
161
              tmpBottom= (y==       0 ? mapBottom:mapBlack);
162

    
163
              mCubes[x][y][z]           = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
164
              cubeVectors[x][y][z]      = new Static3D( TEXTURE_SIZE*(x-nc), TEXTURE_SIZE*(y-nc), TEXTURE_SIZE*(z-nc) );
165
              mQuatScramble[x][y][z]    = new Static4D(0,0,0,1);
166
              mRotationAngle[x][y][z]   = new Dynamic1D();
167
              mRotationAxis[x][y][z]    = new Static3D(1,0,0);
168
              mCurrentPosition[x][y][z] = new Static3D(x,y,z);
169
              mRotateEffect[x][y][z]    = new MatrixEffectRotate(mRotationAngle[x][y][z], mRotationAxis[x][y][z], matrCenter);
170

    
171
              mEffects[x][y][z] = new DistortedEffects();
172
              mEffects[x][y][z].apply(sinkEffect);
173
              mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
174
              mEffects[x][y][z].apply( new MatrixEffectQuaternion(mQuatScramble[x][y][z], matrCenter));
175
              mEffects[x][y][z].apply(mRotateEffect[x][y][z]);
176
              mEffects[x][y][z].apply(quatAEffect);
177
              mEffects[x][y][z].apply(quatCEffect);
178
              mEffects[x][y][z].apply(scaleEffect);
179
              mEffects[x][y][z].apply(moveEffect);
180

    
181
              mNodes[x][y][z] = new DistortedNode(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
182

    
183
              attach(mNodes[x][y][z]);
184
              }
185
            }
186
      }
187

    
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189

    
190
    public void apply(Effect effect, int position)
191
      {
192
      for(int x=0; x<mSize; x++)
193
        for(int y=0; y<mSize; y++)
194
          for(int z=0; z<mSize; z++)
195
            {
196
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
197
              {
198
              mEffects[x][y][z].apply(effect, position);
199
              }
200
            }
201
      }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
    public void remove(long effectID)
206
      {
207
      for(int x=0; x<mSize; x++)
208
        for(int y=0; y<mSize; y++)
209
          for(int z=0; z<mSize; z++)
210
            {
211
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
212
              {
213
              mEffects[x][y][z].abortById(effectID);
214
              }
215
            }
216
      }
217

    
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219

    
220
    public void solve()
221
      {
222
      for(int x=0; x<mSize; x++)
223
        for(int y=0; y<mSize; y++)
224
          for(int z=0; z<mSize; z++)
225
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
226
              {
227
              mQuatScramble[x][y][z].set(0,0,0,1);
228
              mCurrentPosition[x][y][z].set(x,y,z);
229
              }
230
      }
231

    
232
///////////////////////////////////////////////////////////////////////////////////////////////////
233

    
234
    public String print_effects()
235
      {
236
      String str="";
237

    
238
      EffectQueue[] effects = mEffects[0][0][0].getQueues();
239
      EffectQueue matrix      = effects[0];
240
      EffectQueue vertex      = effects[1];
241
      EffectQueue fragment    = effects[2];
242
      EffectQueue postprocess = effects[3];
243

    
244
      str+="MATRIX: ";
245
      int m_len = matrix.getNumEffects();
246
      for(int i=0; i<m_len; i++)
247
        {
248
        str+=(" "+matrix.getEffect(i).getName()+"("+matrix.getEffect(i).getID()+")" );
249
        }
250
      str+='\n';
251

    
252
      str+="VERTEX: ";
253
      int v_len = vertex.getNumEffects();
254
      for(int i=0; i<v_len; i++)
255
        {
256
        str+=(" "+vertex.getEffect(i).getName()+"("+matrix.getEffect(i).getID()+")" );
257
        }
258
      str+='\n';
259

    
260
      str+="FRAGMENT: ";
261
      int f_len = fragment.getNumEffects();
262
      for(int i=0; i<f_len; i++)
263
        {
264
        str+=(" "+fragment.getEffect(i).getName()+"("+matrix.getEffect(i).getID()+")" );
265
        }
266
      str+='\n';
267

    
268
      str+="POSTPROCESS: ";
269
      int p_len = postprocess.getNumEffects();
270
      for(int i=0; i<p_len; i++)
271
        {
272
        str+=(" "+postprocess.getEffect(i).getName()+"("+matrix.getEffect(i).getID()+")" );
273
        }
274
      str+='\n';
275

    
276
      return str;
277
      }
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
    public int getNumEffects(EffectType type)
281
      {
282
      return mEffects[0][0][0].getNumEffects(type);
283
      }
284

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

    
287
    public long addNewRotation(int vector, int row, int angle, long durationMillis, EffectListener listener )
288
      {
289
      Static3D axis = VectX;
290
      long effectID=0;
291
      boolean first = true;
292

    
293
      switch(vector)
294
        {
295
        case VECTX: axis = VectX; break;
296
        case VECTY: axis = VectY; break;
297
        case VECTZ: axis = VectZ; break;
298
        }
299

    
300
      mRotAxis = vector;
301
      mRotRow  = row;
302

    
303
      mRotationAngleStatic.set1(0.0f);
304

    
305
      for(int x=0; x<mSize; x++)
306
        for(int y=0; y<mSize; y++)
307
          for(int z=0; z<mSize; z++)
308
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
309
              {
310
              if( belongsToRotation(x,y,z,vector,mRotRow) )
311
                {
312
                mRotationAxis[x][y][z].set(axis);
313
                mRotationAngle[x][y][z].setDuration(durationMillis);
314
                mRotationAngle[x][y][z].resetToBeginning();
315
                mRotationAngle[x][y][z].add(new Static1D(0));
316
                mRotationAngle[x][y][z].add(new Static1D(angle));
317

    
318
                if( first )
319
                  {
320
                  first = false;
321
                  effectID = mRotateEffect[x][y][z].getID();
322
                  mRotateEffect[x][y][z].notifyWhenFinished(listener);
323
                  }
324
                }
325
              }
326

    
327
      return effectID;
328
      }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
    public int getSize()
333
      {
334
      return mSize;
335
      }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338
// all DistortedTextures, DistortedNodes, DistortedFramebuffers, DistortedScreens and all types of
339
// Meshes HAVE TO be markedForDeletion when they are no longer needed- otherwise we have a major
340
// memory leak.
341

    
342
    void releaseResources()
343
      {
344
      mTexture.markForDeletion();
345

    
346
      for(int x=0; x<mSize; x++)
347
        for(int y=0; y<mSize; y++)
348
          for(int z=0; z<mSize; z++)
349
            {
350
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
351
              {
352
              mCubes[x][y][z].markForDeletion();
353
              mNodes[x][y][z].markForDeletion();
354
              }
355
            }
356
      }
357

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359

    
360
    void addNewRotation(int vector, int row )
361
      {
362
      Static3D axis = VectX;
363

    
364
      switch(vector)
365
        {
366
        case VECTX: axis = VectX; break;
367
        case VECTY: axis = VectY; break;
368
        case VECTZ: axis = VectZ; break;
369
        }
370

    
371
      mRotAxis = vector;
372
      mRotRow  = row;
373

    
374
      mRotationAngleStatic.set1(0.0f);
375

    
376
      for(int x=0; x<mSize; x++)
377
        for(int y=0; y<mSize; y++)
378
          for(int z=0; z<mSize; z++)
379
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
380
              {
381
              if( belongsToRotation(x,y,z,vector,mRotRow) )
382
                {
383
                mRotationAxis[x][y][z].set(axis);
384
                mRotationAngle[x][y][z].add(mRotationAngleStatic);
385
                }
386
              }
387
      }
388

    
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390

    
391
    void continueRotation(float angleInDegrees)
392
      {
393
      mRotationAngleStatic.set1(angleInDegrees);
394
      }
395

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

    
398
    private int computeNearestAngle(float angle)
399
      {
400
      final int NEAREST = 90;
401

    
402
      int tmp = (int)((angle+NEAREST/2)/NEAREST);
403
      if( angle< -(NEAREST/2) ) tmp-=1;
404

    
405
      return NEAREST*tmp;
406
      }
407

    
408
///////////////////////////////////////////////////////////////////////////////////////////////////
409

    
410
    long finishRotationNow(EffectListener listener)
411
      {
412
      boolean first = true;
413
      long effectID=0;
414

    
415
      for(int x=0; x<mSize; x++)
416
        for(int y=0; y<mSize; y++)
417
          for(int z=0; z<mSize; z++)
418
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
419
              {
420
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
421
                {
422
                if( first )
423
                  {
424
                  first = false;
425
                  mRotateEffect[x][y][z].notifyWhenFinished(listener);
426
                  effectID = mRotateEffect[x][y][z].getID();
427
                  int pointNum = mRotationAngle[x][y][z].getNumPoints();
428

    
429
                  if( pointNum>=1 )
430
                    {
431
                    float startingAngle = mRotationAngle[x][y][z].getPoint(pointNum-1).get1();
432
                    int nearestAngleInDegrees = computeNearestAngle(startingAngle);
433
                    mRotationAngleStatic.set1(startingAngle);
434
                    mRotationAngleFinal.set1(nearestAngleInDegrees);
435
                    mRotationAngleMiddle.set1( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
436
                    }
437
                  else
438
                    {
439
                    android.util.Log.e("cube", "ERROR finishing rotation!");
440
                    return 0;
441
                    }
442
                  }
443

    
444
                mRotationAngle[x][y][z].setDuration(POST_ROTATION_MILLISEC);
445
                mRotationAngle[x][y][z].resetToBeginning();
446
                mRotationAngle[x][y][z].removeAll();
447
                mRotationAngle[x][y][z].add(mRotationAngleStatic);
448
                mRotationAngle[x][y][z].add(mRotationAngleMiddle);
449
                mRotationAngle[x][y][z].add(mRotationAngleFinal);
450
                }
451
              }
452

    
453
      return effectID;
454
      }
455

    
456
///////////////////////////////////////////////////////////////////////////////////////////////////
457

    
458
    public void removeRotationNow()
459
      {
460
      float qx=0,qy=0,qz=0;
461
      boolean first = true;
462
      Static4D quat = null;
463

    
464
      switch(mRotAxis)
465
        {
466
        case VECTX: qx=1; break;
467
        case VECTY: qy=1; break;
468
        case VECTZ: qz=1; break;
469
        }
470

    
471
      for(int x=0; x<mSize; x++)
472
        for(int y=0; y<mSize; y++)
473
          for(int z=0; z<mSize; z++)
474
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
475
              {
476
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
477
                {
478
                if( first )
479
                  {
480
                  first = false;
481
                  int pointNum = mRotationAngle[x][y][z].getNumPoints();
482

    
483
                  if( pointNum>=1 )
484
                    {
485
                    float startingAngle = mRotationAngle[x][y][z].getPoint(pointNum-1).get1();
486
                    int nearestAngleInDegrees = computeNearestAngle(startingAngle);
487
                    double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
488
                    float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
489
                    float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
490
                    quat = new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
491
                    }
492
                  else
493
                    {
494
                    android.util.Log.e("cube", "ERROR removing rotation!");
495
                    return;
496
                    }
497
                  }
498

    
499
                mRotationAngle[x][y][z].removeAll();
500
                mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z]));
501
                modifyCurrentPosition(x,y,z,quat);
502
                }
503
              }
504

    
505
      mRotationAngleStatic.set1(0);
506
      }
507

    
508
///////////////////////////////////////////////////////////////////////////////////////////////////
509

    
510
    private float getSinkStrength()
511
      {
512
      switch(mSize)
513
        {
514
        case 1 : return 1.1f;
515
        case 2 : return 1.5f;
516
        case 3 : return 1.8f;
517
        case 4 : return 2.0f;
518
        default: return 3.0f - 4.0f/mSize;
519
        }
520
      }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523

    
524
    private boolean belongsToRotation(int x, int y, int z, int vector, int row)
525
      {
526
      switch(vector)
527
        {
528
        case VECTX: return mCurrentPosition[x][y][z].get1()==row;
529
        case VECTY: return mCurrentPosition[x][y][z].get2()==row;
530
        case VECTZ: return mCurrentPosition[x][y][z].get3()==row;
531
        }
532

    
533
      return false;
534
      }
535

    
536
///////////////////////////////////////////////////////////////////////////////////////////////////
537

    
538
    private void modifyCurrentPosition(int x, int y, int z, Static4D quat)
539
      {
540
      Static3D current = mCurrentPosition[x][y][z];
541
      float diff = 0.5f*(mSize-1);
542
      float cubitCenterX = current.get1() - diff;
543
      float cubitCenterY = current.get2() - diff;
544
      float cubitCenterZ = current.get3() - diff;
545

    
546
      Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
547
      Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
548

    
549
      float rotatedX = rotatedCenter.get1() + diff;
550
      float rotatedY = rotatedCenter.get2() + diff;
551
      float rotatedZ = rotatedCenter.get3() + diff;
552

    
553
      int roundedX = (int)(rotatedX+0.1f);
554
      int roundedY = (int)(rotatedY+0.1f);
555
      int roundedZ = (int)(rotatedZ+0.1f);
556

    
557
      mCurrentPosition[x][y][z].set1(roundedX);
558
      mCurrentPosition[x][y][z].set2(roundedY);
559
      mCurrentPosition[x][y][z].set3(roundedZ);
560
      }
561

    
562
///////////////////////////////////////////////////////////////////////////////////////////////////
563

    
564
    void createTexture()
565
      {
566
      Bitmap bitmap;
567

    
568
      final int S = 128;
569
      final int W = 3*S;
570
      final int H = 2*S;
571
      final int R = S/10;
572
      final int M = S/20;
573

    
574
      Paint paint = new Paint();
575
      bitmap = Bitmap.createBitmap(W,H, Bitmap.Config.ARGB_8888);
576
      Canvas canvas = new Canvas(bitmap);
577

    
578
      paint.setAntiAlias(true);
579
      paint.setTextAlign(Paint.Align.CENTER);
580
      paint.setStyle(Paint.Style.FILL);
581

    
582
      // 3x2 bitmap = 6 squares:
583
      //
584
      // RED     GREEN   BLUE
585
      // YELLOW  WHITE   BROWN
586

    
587
      paint.setColor(0xff000000);                                  // BLACK BACKGROUND
588
      canvas.drawRect(0, 0, W, H, paint);                          //
589

    
590
      paint.setColor(0xffff0000);                                  // RED
591
      canvas.drawRoundRect(    M,   M,   S-M,   S-M, R, R, paint); //
592
      paint.setColor(0xff00ff00);                                  // GREEN
593
      canvas.drawRoundRect(  S+M,   M, 2*S-M,   S-M, R, R, paint); //
594
      paint.setColor(0xff0000ff);                                  // BLUE
595
      canvas.drawRoundRect(2*S+M,   M, 3*S-M,   S-M, R, R, paint); //
596
      paint.setColor(0xffffff00);                                  // YELLOW
597
      canvas.drawRoundRect(    M, S+M,   S-M, 2*S-M, R, R, paint); //
598
      paint.setColor(0xffffffff);                                  // WHITE
599
      canvas.drawRoundRect(  S+M, S+M, 2*S-M, 2*S-M, R, R, paint); //
600
      paint.setColor(0xffb5651d);                                  // BROWN
601
      canvas.drawRoundRect(2*S+M, S+M, 3*S-M, 2*S-M, R, R, paint); //
602

    
603
      mTexture.setTexture(bitmap);
604
      }
605

    
606
///////////////////////////////////////////////////////////////////////////////////////////////////
607

    
608
    void recomputeScaleFactor(int screenWidth, int screenHeight, float size)
609
      {
610
      int texW = mNodeTexture.getWidth();
611
      int texH = mNodeTexture.getHeight();
612

    
613
      if( (float)texH/texW > (float)screenHeight/screenWidth )
614
        {
615
        int w = (screenHeight*texW)/texH;
616
        float factor = (float)screenHeight/texH;
617
        mNodeMove.set((screenWidth-w)*0.5f ,0, 0);
618
        mNodeScale.set(factor,factor,factor);
619
        }
620
      else
621
        {
622
        int h = (screenWidth*texH)/texW;
623
        float factor = (float)screenWidth/texW;
624
        mNodeMove.set(0,(screenHeight-h)*0.5f,0);
625
        mNodeScale.set(factor,factor,factor);
626
        }
627

    
628
      float scaleFactor = (size/(TEXTURE_SIZE*mSize)) * (float)texW/(screenWidth>screenHeight ? screenHeight:screenWidth);
629

    
630
      mMove.set( texW*0.5f , texH*0.5f , 0.0f );
631
      mScale.set(scaleFactor,scaleFactor,scaleFactor);
632
      }
633
}
(3-3/7)