Project

General

Profile

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

magiccube / src / main / java / org / distorted / magic / RubikRenderer.java @ aa171dee

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.magic;
21

    
22
import android.content.SharedPreferences;
23
import android.opengl.GLSurfaceView;
24
import android.os.Bundle;
25

    
26
import org.distorted.dialog.RubikDialogNewRecord;
27
import org.distorted.dialog.RubikDialogSolved;
28
import org.distorted.effect.BaseEffect;
29
import org.distorted.library.effect.VertexEffectSink;
30
import org.distorted.library.main.DistortedLibrary;
31
import org.distorted.library.main.DistortedScreen;
32
import org.distorted.library.message.EffectListener;
33
import org.distorted.object.RubikObject;
34
import org.distorted.object.RubikObjectList;
35
import org.distorted.scores.RubikScores;
36
import org.distorted.uistate.RubikState;
37
import org.distorted.uistate.RubikStateSolving;
38

    
39
import javax.microedition.khronos.egl.EGLConfig;
40
import javax.microedition.khronos.opengles.GL10;
41

    
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

    
44
public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
45
{
46
    public static final int NODE_FBO_SIZE = 600;
47

    
48
    private RubikSurfaceView mView;
49
    private DistortedScreen mScreen;
50
    private RubikObjectList mNextObject;
51
    private int mNextSize;
52
    private int mScrambleObjectNum;
53
    private long mRotationFinishedID;
54
    private long[] mEffectID;
55
    private boolean mFinishRotation, mRemoveRotation, mSetQuatCurrent, mSetQuatAccumulated;
56
    private boolean mChangeObject, mSolveObject, mScrambleObject;
57
    private boolean mCanRotate, mCanDrag, mCanUI;
58
    private boolean mIsSolved;
59
    private boolean mIsNewRecord;
60
    private long mNewRecord;
61
    private RubikObject mOldObject, mNewObject;
62
    private int mScreenWidth, mScreenHeight;
63
    private SharedPreferences mPreferences;
64
    private String mNextMoves;
65

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

    
68
    RubikRenderer(RubikSurfaceView v)
69
      {
70
      mView = v;
71
      mScreen = new DistortedScreen();
72

    
73
      mOldObject = null;
74
      mNewObject = null;
75

    
76
      mScreenWidth = mScreenHeight = 0;
77
      mScrambleObjectNum = 0;
78

    
79
      mFinishRotation     = false;
80
      mRemoveRotation     = false;
81
      mSetQuatCurrent     = false;
82
      mSetQuatAccumulated = false;
83
      mChangeObject       = false;
84
      mSolveObject        = false;
85
      mScrambleObject     = false;
86

    
87
      mCanRotate   = true;
88
      mCanDrag     = true;
89
      mCanUI       = true;
90

    
91
      mEffectID = new long[BaseEffect.Type.LENGTH];
92
      }
93

    
94
///////////////////////////////////////////////////////////////////////////////////////////////////
95

    
96
   private void createObjectNow(RubikObjectList object, int size, String moves)
97
     {
98
     boolean firstTime = (mNewObject==null);
99

    
100
     if( mOldObject!=null ) mOldObject.releaseResources();
101
     mOldObject = mNewObject;
102

    
103
     mNewObject = object.create(size, mView.getQuatCurrent(), mView.getQuatAccumulated(), moves);
104
     mNewObject.createTexture();
105
     mView.setMovement(object.getObjectMovementClass());
106

    
107
     if( firstTime ) mNewObject.restorePreferences(mPreferences);
108

    
109
     if( mScreenWidth!=0 )
110
       {
111
       mNewObject.recomputeScaleFactor(mScreenWidth, mScreenHeight);
112
       }
113

    
114
     mIsSolved = true;
115
     }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118
// do all 'adjustable' effects (SizeChange, Solve, Scramble)
119

    
120
   private void doEffectNow(BaseEffect.Type type)
121
     {
122
     int index = type.ordinal();
123

    
124
     try
125
       {
126
       mEffectID[index] = type.startEffect(this);
127
       }
128
     catch( Exception ex )
129
       {
130
       android.util.Log.e("renderer", "exception starting effect: "+ex.getMessage());
131

    
132
       mCanUI     = true;
133
       mCanRotate = true;
134
       mCanDrag   = true;
135
       }
136
     }
137

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

    
140
   void savePreferences(SharedPreferences.Editor editor)
141
     {
142
     if( mNewObject!=null )
143
       {
144
       mNewObject.savePreferences(editor);
145
       }
146
     }
147

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

    
150
   void restorePreferences(SharedPreferences preferences)
151
     {
152
     mPreferences = preferences;
153
     }
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156
// no this will not race with onDrawFrame
157

    
158
   void finishRotation()
159
     {
160
     mFinishRotation = true;
161
     }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

    
165
   void changeObject(RubikObjectList object, int size, String moves)
166
     {
167
     if( size>0 )
168
       {
169
       mChangeObject = true;
170
       mNextObject = object;
171
       mNextSize   = size;
172
       mNextMoves  = moves;
173
       }
174
     }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
   void scrambleObject(int num)
179
     {
180
     if( mCanUI )
181
       {
182
       mScrambleObject = true;
183
       mScrambleObjectNum = num;
184
       }
185
     }
186

    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188

    
189
   void solveObject()
190
     {
191
     if( mCanUI )
192
       {
193
       mSolveObject = true;
194
       }
195
     }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198

    
199
   boolean canRotate()
200
     {
201
     return mCanRotate;
202
     }
203

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

    
206
   boolean canDrag()
207
     {
208
     return mCanDrag;
209
     }
210

    
211
///////////////////////////////////////////////////////////////////////////////////////////////////
212

    
213
   void setQuatCurrentOnNextRender()
214
     {
215
     mSetQuatCurrent = true;
216
     }
217

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

    
220
   void setQuatAccumulatedOnNextRender()
221
     {
222
     mSetQuatAccumulated = true;
223
     }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226
// various things are done here delayed, 'after the next render' as not to be done mid-render and
227
// cause artifacts.
228

    
229
   @Override
230
   public void onDrawFrame(GL10 glUnused)
231
     {
232
     mScreen.render( System.currentTimeMillis() );
233

    
234
     if( mSetQuatCurrent )
235
       {
236
       mSetQuatCurrent = false;
237
       mView.setQuatCurrent();
238
       }
239

    
240
     if( mSetQuatAccumulated )
241
       {
242
       mSetQuatAccumulated = false;
243
       mView.setQuatAccumulated();
244
       }
245

    
246
     if( mFinishRotation )
247
       {
248
       mFinishRotation = false;
249
       mCanRotate      = false;
250
       mCanUI          = false;
251
       mRotationFinishedID = mNewObject.finishRotationNow(this);
252

    
253
       if( mRotationFinishedID==0 ) // failed to add effect - should never happen
254
         {
255
         mCanRotate = true;
256
         mCanUI     = true;
257
         }
258
       }
259

    
260
     if( mRemoveRotation )
261
       {
262
       mRemoveRotation=false;
263
       mNewObject.removeRotationNow();
264

    
265
       boolean solved = mNewObject.isSolved();
266

    
267
       if( solved && !mIsSolved )
268
         {
269
         if( RubikState.getCurrentState()==RubikState.SOLV )
270
           {
271
           RubikStateSolving solving = (RubikStateSolving)RubikState.SOLV.getStateClass();
272
           mNewRecord = solving.stopCounting((RubikActivity)mView.getContext());
273

    
274
           if( mNewRecord< 0 )
275
             {
276
             mNewRecord = -mNewRecord;
277
             mIsNewRecord = false;
278
             }
279
           else
280
             {
281
             mIsNewRecord = true;
282
             }
283
           }
284

    
285
         mCanDrag   = true;
286
         mCanRotate = false;
287
         mCanUI     = false;
288
         doEffectNow( BaseEffect.Type.WIN );
289
         }
290
       else
291
         {
292
         mCanRotate = true;
293
         mCanUI     = true;
294
         }
295

    
296
       mIsSolved = solved;
297
       }
298

    
299
     if( mChangeObject )
300
       {
301
       mChangeObject = false;
302
       mCanDrag      = false;
303
       mCanRotate    = false;
304
       mCanUI        = false;
305

    
306
       if( mNewObject==null )
307
         {
308
         createObjectNow(mNextObject, mNextSize, mNextMoves);
309
         doEffectNow( BaseEffect.Type.SIZECHANGE );
310
         }
311
       else
312
         {
313
         RubikObjectList list = mNewObject.getObjectList();
314
         int size = mNewObject.getSize();
315

    
316
         if (list!=mNextObject || mNextSize!=size)
317
           {
318
           createObjectNow(mNextObject, mNextSize, mNextMoves);
319
           doEffectNow( BaseEffect.Type.SIZECHANGE );
320
           }
321
         else
322
           {
323
           mNewObject.initializeObject(mNextMoves);
324
           }
325
         }
326
       }
327

    
328
     if( mSolveObject )
329
       {
330
       mSolveObject    = false;
331
       mCanDrag        = false;
332
       mCanRotate      = false;
333
       mCanUI          = false;
334
       doEffectNow( BaseEffect.Type.SOLVE );
335
       }
336

    
337
     if( mScrambleObject )
338
       {
339
       mScrambleObject = false;
340
       mCanDrag        = false;
341
       mCanRotate      = false;
342
       mCanUI          = false;
343
       mIsSolved       = false;
344
       RubikScores.getInstance().incrementNumPlays();
345
       doEffectNow( BaseEffect.Type.SCRAMBLE );
346
       }
347
     }
348

    
349
///////////////////////////////////////////////////////////////////////////////////////////////////
350

    
351
   @Override
352
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
353
      {
354
      if( mNewObject!=null ) mNewObject.createTexture();
355

    
356
      mScreen.resize(width, height);
357
      mView.setScreenSize(width,height);
358

    
359
      if( mNewObject!=null )
360
        {
361
        mNewObject.recomputeScaleFactor(width,height);
362
        }
363

    
364
      mScreenHeight = height;
365
      mScreenWidth  = width;
366
      }
367

    
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369

    
370
   @Override
371
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
372
      {
373
      VertexEffectSink.enable();
374
      BaseEffect.Type.enableEffects();
375

    
376
      try
377
        {
378
        DistortedLibrary.onCreate(mView.getContext());
379
        }
380
      catch(Exception ex)
381
        {
382
        android.util.Log.e("Rubik", ex.getMessage() );
383
        }
384
      }
385

    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387
// PUBLIC API
388
///////////////////////////////////////////////////////////////////////////////////////////////////
389

    
390
   public void effectFinished(final long effectID)
391
     {
392
     if( effectID == mRotationFinishedID )
393
       {
394
       mRemoveRotation = true;
395
       }
396
     else
397
       {
398
       for(int i=0; i<BaseEffect.Type.LENGTH; i++)
399
         {
400
         if( effectID == mEffectID[i] )
401
           {
402
           mCanRotate   = true;
403
           mCanDrag     = true;
404
           mCanUI       = true;
405

    
406
           if( i==BaseEffect.Type.SCRAMBLE.ordinal() )
407
             {
408
             final RubikActivity act = (RubikActivity)mView.getContext();
409

    
410
             act.runOnUiThread(new Runnable()
411
               {
412
               @Override
413
               public void run()
414
                 {
415
                 RubikState.switchState( act, RubikState.SOLV);
416
                 }
417
               });
418
             }
419

    
420
           if( i==BaseEffect.Type.WIN.ordinal() )
421
             {
422
             if( RubikState.getCurrentState()==RubikState.SOLV )
423
               {
424
               final RubikActivity act = (RubikActivity)mView.getContext();
425
               Bundle bundle = new Bundle();
426
               bundle.putLong("time", mNewRecord );
427

    
428
               if( mIsNewRecord )
429
                 {
430
                 RubikDialogNewRecord dialog = new RubikDialogNewRecord();
431
                 dialog.setArguments(bundle);
432
                 dialog.show( act.getSupportFragmentManager(), null);
433
                 }
434
               else
435
                 {
436
                 RubikDialogSolved dialog = new RubikDialogSolved();
437
                 dialog.setArguments(bundle);
438
                 dialog.show( act.getSupportFragmentManager(), null);
439
                 }
440
               }
441
             }
442

    
443
           break;
444
           }
445
         }
446
       }
447
     }
448

    
449
///////////////////////////////////////////////////////////////////////////////////////////////////
450

    
451
   public RubikObject getObject()
452
     {
453
     return mNewObject;
454
     }
455

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

    
458
   public RubikObject getOldObject()
459
     {
460
     return mOldObject;
461
     }
462

    
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464

    
465
   public DistortedScreen getScreen()
466
     {
467
     return mScreen;
468
     }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471

    
472
   public int getNumScrambles()
473
     {
474
     return mScrambleObjectNum;
475
     }
476
}
(2-2/3)