Project

General

Profile

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

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

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

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

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

    
72
      mOldObject = null;
73
      mNewObject = null;
74

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

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

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

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

    
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94

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

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

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

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

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

    
113
     mIsSolved = true;
114
     }
115

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

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

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

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

    
137
///////////////////////////////////////////////////////////////////////////////////////////////////
138

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

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

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

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

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

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163

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

    
174
     return false;
175
     }
176

    
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178

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

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

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

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
   void setCanRotate(boolean can)
201
     {
202
     mCanRotate = can;
203
     }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

    
207
   boolean canRotate()
208
     {
209
     return mCanRotate;
210
     }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
   boolean canDrag()
215
     {
216
     return mCanDrag;
217
     }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
   void setQuatCurrentOnNextRender()
222
     {
223
     mSetQuatCurrent = true;
224
     }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
   void setQuatAccumulatedOnNextRender()
229
     {
230
     mSetQuatAccumulated = true;
231
     }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234
// various things are done here delayed, 'after the next render' as not to be done mid-render and
235
// cause artifacts.
236

    
237
   @Override
238
   public void onDrawFrame(GL10 glUnused)
239
     {
240
     mScreen.render( System.currentTimeMillis() );
241

    
242
     if( mSetQuatCurrent )
243
       {
244
       mSetQuatCurrent = false;
245
       mView.setQuatCurrent();
246
       }
247

    
248
     if( mSetQuatAccumulated )
249
       {
250
       mSetQuatAccumulated = false;
251
       mView.setQuatAccumulated();
252
       }
253

    
254
     if( mFinishRotation )
255
       {
256
       mFinishRotation = false;
257
       mCanRotate      = false;
258
       mCanUI          = false;
259
       mRotationFinishedID = mNewObject.finishRotationNow(this);
260

    
261
       if( mRotationFinishedID==0 ) // failed to add effect - should never happen
262
         {
263
         mCanRotate = true;
264
         mCanUI     = true;
265
         }
266
       }
267

    
268
     if( mRemoveRotation )
269
       {
270
       mRemoveRotation=false;
271
       mNewObject.removeRotationNow();
272

    
273
       boolean solved = mNewObject.isSolved();
274

    
275
       if( solved && !mIsSolved )
276
         {
277
         if( RubikState.getCurrentState()==RubikState.SOLV )
278
           {
279
           RubikStateSolving solving = (RubikStateSolving)RubikState.SOLV.getStateClass();
280
           mNewRecord = solving.stopCounting((RubikActivity)mView.getContext());
281

    
282
           if( mNewRecord< 0 )
283
             {
284
             mNewRecord = -mNewRecord;
285
             mIsNewRecord = false;
286
             }
287
           else
288
             {
289
             mIsNewRecord = true;
290
             }
291
           }
292

    
293
         mCanDrag   = true;
294
         mCanRotate = false;
295
         mCanUI     = false;
296
         doEffectNow( BaseEffect.Type.WIN );
297
         }
298
       else
299
         {
300
         mCanRotate = true;
301
         mCanUI     = true;
302
         }
303

    
304
       mIsSolved = solved;
305
       }
306

    
307
     if( mChangeObject )
308
       {
309
       mChangeObject = false;
310
       mCanDrag      = false;
311
       mCanRotate    = false;
312
       mCanUI        = false;
313
       createObjectNow(mNextObject, mNextSize);
314
       doEffectNow( BaseEffect.Type.SIZECHANGE );
315
       }
316

    
317
     if( mSolveObject )
318
       {
319
       mSolveObject    = false;
320
       mCanDrag        = false;
321
       mCanRotate      = false;
322
       mCanUI          = false;
323
       doEffectNow( BaseEffect.Type.SOLVE );
324
       }
325

    
326
     if( mScrambleObject )
327
       {
328
       mScrambleObject = false;
329
       mCanDrag        = false;
330
       mCanRotate      = false;
331
       mCanUI          = false;
332
       mIsSolved       = false;
333
       RubikScores.getInstance().incrementNumPlays();
334
       doEffectNow( BaseEffect.Type.SCRAMBLE );
335
       }
336
     }
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339

    
340
   @Override
341
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
342
      {
343
      if( mNewObject!=null ) mNewObject.createTexture();
344

    
345
      mScreen.resize(width, height);
346
      mView.setScreenSize(width,height);
347

    
348
      if( mNewObject!=null )
349
        {
350
        mNewObject.recomputeScaleFactor(width,height);
351
        }
352

    
353
      mScreenHeight = height;
354
      mScreenWidth  = width;
355
      }
356

    
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358

    
359
   @Override
360
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
361
      {
362
      VertexEffectSink.enable();
363
      BaseEffect.Type.enableEffects();
364

    
365
      try
366
        {
367
        DistortedLibrary.onCreate(mView.getContext());
368
        }
369
      catch(Exception ex)
370
        {
371
        android.util.Log.e("Rubik", ex.getMessage() );
372
        }
373
      }
374

    
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376
// PUBLIC API
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

    
379
   public void effectFinished(final long effectID)
380
     {
381
     if( effectID == mRotationFinishedID )
382
       {
383
       mRemoveRotation = true;
384
       }
385
     else
386
       {
387
       for(int i=0; i<BaseEffect.Type.LENGTH; i++)
388
         {
389
         if( effectID == mEffectID[i] )
390
           {
391
           mCanRotate   = true;
392
           mCanDrag     = true;
393
           mCanUI       = true;
394

    
395
           if( i==BaseEffect.Type.SCRAMBLE.ordinal() )
396
             {
397
             final RubikActivity act = (RubikActivity)mView.getContext();
398

    
399
             act.runOnUiThread(new Runnable()
400
               {
401
               @Override
402
               public void run()
403
                 {
404
                 RubikState.switchState( act, RubikState.SOLV);
405
                 }
406
               });
407
             }
408

    
409
           if( i==BaseEffect.Type.WIN.ordinal() )
410
             {
411
             if( RubikState.getCurrentState()==RubikState.SOLV )
412
               {
413
               final RubikActivity act = (RubikActivity)mView.getContext();
414
               Bundle bundle = new Bundle();
415
               bundle.putLong("time", mNewRecord );
416

    
417
               if( mIsNewRecord )
418
                 {
419
                 RubikDialogNewRecord dialog = new RubikDialogNewRecord();
420
                 dialog.setArguments(bundle);
421
                 dialog.show( act.getSupportFragmentManager(), null);
422
                 }
423
               else
424
                 {
425
                 RubikDialogSolved dialog = new RubikDialogSolved();
426
                 dialog.setArguments(bundle);
427
                 dialog.show( act.getSupportFragmentManager(), null);
428
                 }
429
               }
430
             }
431

    
432
           break;
433
           }
434
         }
435
       }
436
     }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
   public RubikObject getObject()
441
     {
442
     return mNewObject;
443
     }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

    
447
   public RubikObject getOldObject()
448
     {
449
     return mOldObject;
450
     }
451

    
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453

    
454
   public DistortedScreen getScreen()
455
     {
456
     return mScreen;
457
     }
458

    
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

    
461
   public int getNumScrambles()
462
     {
463
     return mScrambleObjectNum;
464
     }
465
}
(2-2/3)