Project

General

Profile

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

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

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.RubikDialogSolved;
27
import org.distorted.effect.BaseEffect;
28
import org.distorted.library.effect.VertexEffectSink;
29
import org.distorted.library.main.DistortedLibrary;
30
import org.distorted.library.main.DistortedScreen;
31
import org.distorted.library.message.EffectListener;
32
import org.distorted.object.RubikObject;
33
import org.distorted.object.RubikObjectList;
34
import org.distorted.scores.RubikScores;
35
import org.distorted.uistate.RubikState;
36
import org.distorted.uistate.RubikStateSolving;
37

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

    
41
///////////////////////////////////////////////////////////////////////////////////////////////////
42

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

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

    
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

    
66
    RubikRenderer(RubikSurfaceView v)
67
      {
68
      mView = v;
69
      mScreen = new DistortedScreen();
70

    
71
      mOldObject = null;
72
      mNewObject = null;
73

    
74
      mScreenWidth = mScreenHeight = 0;
75
      mScrambleObjectNum = 0;
76

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

    
85
      mCanRotate   = true;
86
      mCanDrag     = true;
87
      mCanUI       = true;
88

    
89
      mEffectID = new long[BaseEffect.Type.LENGTH];
90
      }
91

    
92
///////////////////////////////////////////////////////////////////////////////////////////////////
93

    
94
   private void createObjectNow(RubikObjectList object, int size)
95
     {
96
     boolean firstTime = (mNewObject==null);
97

    
98
     if( mOldObject!=null ) mOldObject.releaseResources();
99
     mOldObject = mNewObject;
100

    
101
     mNewObject = object.create(size, mView.getQuatCurrent(), mView.getQuatAccumulated());
102
     mNewObject.createTexture();
103
     mView.setMovement(object.getObjectMovementClass());
104

    
105
     if( firstTime ) mNewObject.restorePreferences(mPreferences);
106

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

    
112
     mIsSolved = true;
113
     }
114

    
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116
// do all 'adjustable' effects (SizeChange, Solve, Scramble)
117

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

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

    
130
       mCanUI     = true;
131
       mCanRotate = true;
132
       mCanDrag   = true;
133
       }
134
     }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

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

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
   void restorePreferences(SharedPreferences preferences)
149
     {
150
     mPreferences = preferences;
151
     }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154
// no this will not race with onDrawFrame
155

    
156
   void finishRotation()
157
     {
158
     mFinishRotation = true;
159
     }
160

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

    
163
   boolean createObject(RubikObjectList object, int size)
164
     {
165
     if( mCanDrag && mCanRotate && (object!=mNextObject || mNextSize!=size) && size>0 )
166
       {
167
       mChangeObject = true;
168
       mNextObject = object;
169
       mNextSize   = size;
170
       return true;
171
       }
172

    
173
     return false;
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
       createObjectNow(mNextObject, mNextSize);
306
       doEffectNow( BaseEffect.Type.SIZECHANGE );
307
       }
308

    
309
     if( mSolveObject )
310
       {
311
       mSolveObject    = false;
312
       mCanDrag        = false;
313
       mCanRotate      = false;
314
       mCanUI          = false;
315
       doEffectNow( BaseEffect.Type.SOLVE );
316
       }
317

    
318
     if( mScrambleObject )
319
       {
320
       mScrambleObject = false;
321
       mCanDrag        = false;
322
       mCanRotate      = false;
323
       mCanUI          = false;
324
       mIsSolved       = false;
325
       RubikScores.getInstance().incrementNumPlays();
326
       doEffectNow( BaseEffect.Type.SCRAMBLE );
327
       }
328
     }
329

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

    
332
   @Override
333
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
334
      {
335
      if( mNewObject!=null ) mNewObject.createTexture();
336

    
337
      mScreen.resize(width, height);
338
      mView.setScreenSize(width,height);
339

    
340
      if( mNewObject!=null )
341
        {
342
        mNewObject.recomputeScaleFactor(width,height);
343
        }
344

    
345
      mScreenHeight = height;
346
      mScreenWidth  = width;
347
      }
348

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

    
351
   @Override
352
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
353
      {
354
      VertexEffectSink.enable();
355
      BaseEffect.Type.enableEffects();
356

    
357
      try
358
        {
359
        DistortedLibrary.onCreate(mView.getContext());
360
        }
361
      catch(Exception ex)
362
        {
363
        android.util.Log.e("Rubik", ex.getMessage() );
364
        }
365
      }
366

    
367
///////////////////////////////////////////////////////////////////////////////////////////////////
368
// PUBLIC API
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370

    
371
   public void effectFinished(final long effectID)
372
     {
373
     if( effectID == mRotationFinishedID )
374
       {
375
       mRemoveRotation = true;
376
       }
377
     else
378
       {
379
       for(int i=0; i<BaseEffect.Type.LENGTH; i++)
380
         {
381
         if( effectID == mEffectID[i] )
382
           {
383
           mCanRotate   = true;
384
           mCanDrag     = true;
385
           mCanUI       = true;
386

    
387
           if( i==BaseEffect.Type.SCRAMBLE.ordinal() )
388
             {
389
             final RubikActivity act = (RubikActivity)mView.getContext();
390

    
391
             act.runOnUiThread(new Runnable()
392
               {
393
               @Override
394
               public void run()
395
                 {
396
                 RubikState.switchState( act, RubikState.SOLV);
397
                 }
398
               });
399
             }
400

    
401
           if( i==BaseEffect.Type.WIN.ordinal() )
402
             {
403
             if( RubikState.getCurrentState()==RubikState.SOLV )
404
               {
405
               final RubikActivity act = (RubikActivity)mView.getContext();
406

    
407
               if( mIsNewRecord )
408
                 {
409
                 RubikDialogSolved dialog = new RubikDialogSolved();
410

    
411
                 Bundle bundle = new Bundle();
412
                 bundle.putLong("time", mNewRecord );
413
                 dialog.setArguments(bundle);
414
                 dialog.show( act.getSupportFragmentManager(), null);
415
                 }
416
               else
417
                 {
418
                 RubikDialogSolved dialog = new RubikDialogSolved();
419

    
420
                 Bundle bundle = new Bundle();
421
                 bundle.putLong("time", mNewRecord );
422
                 dialog.setArguments(bundle);
423
                 dialog.show( act.getSupportFragmentManager(), null);
424
                 }
425
               }
426
             }
427

    
428
           break;
429
           }
430
         }
431
       }
432
     }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

    
436
   public RubikObject getObject()
437
     {
438
     return mNewObject;
439
     }
440

    
441
///////////////////////////////////////////////////////////////////////////////////////////////////
442

    
443
   public RubikObject getOldObject()
444
     {
445
     return mOldObject;
446
     }
447

    
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449

    
450
   public DistortedScreen getScreen()
451
     {
452
     return mScreen;
453
     }
454

    
455
///////////////////////////////////////////////////////////////////////////////////////////////////
456

    
457
   public int getNumScrambles()
458
     {
459
     return mScrambleObjectNum;
460
     }
461
}
(2-2/3)