Project

General

Profile

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

magiccube / src / main / java / org / distorted / magic / RubikRenderer.java @ 74686c71

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

    
25
import org.distorted.effect.BaseEffect;
26
import org.distorted.library.effect.VertexEffectSink;
27
import org.distorted.library.main.DistortedLibrary;
28
import org.distorted.library.main.DistortedScreen;
29
import org.distorted.library.message.EffectListener;
30
import org.distorted.object.RubikObject;
31
import org.distorted.object.RubikObjectList;
32
import org.distorted.uistate.RubikState;
33
import org.distorted.uistate.RubikStateSolving;
34

    
35
import javax.microedition.khronos.egl.EGLConfig;
36
import javax.microedition.khronos.opengles.GL10;
37

    
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39

    
40
public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
41
{
42
    static final float CAMERA_DISTANCE = 0.6f;  // 0.6 of the length of min(scrHeight,scrWidth)
43
    public static final int TEXTURE_SIZE = 600;
44

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

    
59
///////////////////////////////////////////////////////////////////////////////////////////////////
60

    
61
    RubikRenderer(RubikSurfaceView v)
62
      {
63
      mView = v;
64
      mScreen = new DistortedScreen();
65

    
66
      mOldObject = null;
67
      mNewObject = null;
68

    
69
      mScreenWidth = mScreenHeight = 0;
70
      mScrambleObjectNum = 0;
71

    
72
      mFinishRotation     = false;
73
      mRemoveRotation     = false;
74
      mSetQuatCurrent     = false;
75
      mSetQuatAccumulated = false;
76
      mChangeObject       = false;
77
      mSolveObject        = false;
78
      mScrambleObject     = false;
79

    
80
      mCanRotate   = true;
81
      mCanDrag     = true;
82
      mCanUI       = true;
83

    
84
      mEffectID = new long[BaseEffect.Type.LENGTH];
85
      }
86

    
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

    
89
   private void createObjectNow(RubikObjectList object)
90
     {
91
     boolean firstTime = (mNewObject==null);
92

    
93
     if( mOldObject!=null ) mOldObject.releaseResources();
94
     mOldObject = mNewObject;
95

    
96
     mNewObject = object.create(mView.getQuatCurrent(), mView.getQuatAccumulated());
97
     mNewObject.createTexture();
98
     mView.setMovement(object.getObjectMovementClass());
99

    
100
     if( firstTime ) mNewObject.restorePreferences(mPreferences);
101

    
102
     if( mScreenWidth!=0 )
103
       {
104
       mNewObject.recomputeScaleFactor(mScreenWidth, mScreenHeight);
105
       }
106

    
107
     mIsSolved = true;
108
     }
109

    
110
///////////////////////////////////////////////////////////////////////////////////////////////////
111
// do all 'adjustable' effects (SizeChange, Solve, Scramble)
112

    
113
   private void doEffectNow(BaseEffect.Type type)
114
     {
115
     int index = type.ordinal();
116

    
117
     try
118
       {
119
       mEffectID[index] = type.startEffect(this);
120
       }
121
     catch( Exception ex )
122
       {
123
       android.util.Log.e("renderer", "exception starting effect: "+ex.getMessage());
124

    
125
       mCanUI     = true;
126
       mCanRotate = true;
127
       mCanDrag   = true;
128
       }
129
     }
130

    
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132

    
133
   void savePreferences(SharedPreferences.Editor editor)
134
     {
135
     mNewObject.savePreferences(editor);
136
     }
137

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

    
140
   void restorePreferences(SharedPreferences preferences)
141
     {
142
     mPreferences = preferences;
143
     }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146
// no this will not race with onDrawFrame
147

    
148
   void finishRotation()
149
     {
150
     mFinishRotation = true;
151
     }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

    
155
   boolean createObject(RubikObjectList object)
156
     {
157
     if( mCanDrag && mCanRotate && object!=mNextObject )
158
       {
159
       mChangeObject = true;
160
       mNextObject = object;
161
       return true;
162
       }
163

    
164
     return false;
165
     }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

    
169
   void scrambleObject(int num)
170
     {
171
     if( mCanUI )
172
       {
173
       mScrambleObject = true;
174
       mScrambleObjectNum = num;
175
       }
176
     }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
   void solveObject()
181
     {
182
     if( mCanUI )
183
       {
184
       mSolveObject = true;
185
       }
186
     }
187

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

    
190
   boolean canRotate()
191
     {
192
     return mCanRotate;
193
     }
194

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196

    
197
   boolean canDrag()
198
     {
199
     return mCanDrag;
200
     }
201

    
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203

    
204
   void setQuatCurrentOnNextRender()
205
     {
206
     mSetQuatCurrent = true;
207
     }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

    
211
   void setQuatAccumulatedOnNextRender()
212
     {
213
     mSetQuatAccumulated = true;
214
     }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217
// various things are done here delayed, 'after the next render' as not to be done mid-render and
218
// cause artifacts.
219

    
220
   @Override
221
   public void onDrawFrame(GL10 glUnused)
222
     {
223
     mScreen.render( System.currentTimeMillis() );
224

    
225
     if( mSetQuatCurrent )
226
       {
227
       mSetQuatCurrent = false;
228
       mView.setQuatCurrent();
229
       }
230

    
231
     if( mSetQuatAccumulated )
232
       {
233
       mSetQuatAccumulated = false;
234
       mView.setQuatAccumulated();
235
       }
236

    
237
     if( mFinishRotation )
238
       {
239
       mFinishRotation = false;
240
       mCanRotate      = false;
241
       mCanUI          = false;
242
       mRotationFinishedID = mNewObject.finishRotationNow(this);
243
       }
244

    
245
     if( mRemoveRotation )
246
       {
247
       mRemoveRotation=false;
248
       mNewObject.removeRotationNow();
249

    
250
       boolean solved = mNewObject.isSolved();
251

    
252
       if( solved && !mIsSolved )
253
         {
254
         if( RubikState.getCurrentState()==RubikState.SOLV )
255
           {
256
           RubikStateSolving solving = (RubikStateSolving)RubikState.SOLV.getStateClass();
257
           long time = solving.stopCounting();
258
           android.util.Log.e("renderer", "solving time: "+time+" milliseconds");
259
           }
260

    
261
         mCanDrag   = true;
262
         mCanRotate = false;
263
         mCanUI     = false;
264
         doEffectNow( BaseEffect.Type.WIN );
265
         }
266
       else
267
         {
268
         mCanRotate = true;
269
         mCanUI     = true;
270
         }
271

    
272
       mIsSolved = solved;
273
       }
274

    
275
     if( mChangeObject )
276
       {
277
       mChangeObject = false;
278
       mCanDrag      = false;
279
       mCanRotate    = false;
280
       mCanUI        = false;
281
       createObjectNow(mNextObject);
282
       doEffectNow( BaseEffect.Type.SIZECHANGE );
283
       }
284

    
285
     if( mSolveObject )
286
       {
287
       mSolveObject    = false;
288
       mCanDrag        = false;
289
       mCanRotate      = false;
290
       mCanUI          = false;
291
       doEffectNow( BaseEffect.Type.SOLVE );
292
       }
293

    
294
     if( mScrambleObject )
295
       {
296
       mScrambleObject = false;
297
       mCanDrag        = false;
298
       mCanRotate      = false;
299
       mCanUI          = false;
300
       doEffectNow( BaseEffect.Type.SCRAMBLE );
301
       }
302
     }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

    
306
   @Override
307
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
308
      {
309
      if( mNewObject!=null ) mNewObject.createTexture();
310

    
311
      double halfFOVInRadians = Math.atan( 1.0f/(2*CAMERA_DISTANCE) );
312
      float fovInDegrees = (float)(2*halfFOVInRadians*(180/Math.PI));
313

    
314
      mScreen.setProjection( fovInDegrees, 0.1f);
315
      mScreen.resize(width, height);
316
      mView.setScreenSize(width,height);
317

    
318
      if( mNewObject!=null )
319
        {
320
        mNewObject.recomputeScaleFactor(width,height);
321
        }
322

    
323
      mScreenHeight = height;
324
      mScreenWidth  = width;
325
      }
326

    
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328

    
329
   @Override
330
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
331
      {
332
      VertexEffectSink.enable();
333
      BaseEffect.Type.enableEffects();
334

    
335
      try
336
        {
337
        DistortedLibrary.onCreate(mView.getContext());
338
        }
339
      catch(Exception ex)
340
        {
341
        android.util.Log.e("Rubik", ex.getMessage() );
342
        }
343
      }
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346
// PUBLIC API
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

    
349
   public void effectFinished(final long effectID)
350
     {
351
     if( effectID == mRotationFinishedID )
352
       {
353
       mRemoveRotation = true;
354
       }
355
     else
356
       {
357
       for(int i=0; i<BaseEffect.Type.LENGTH; i++)
358
         {
359
         if( effectID == mEffectID[i] )
360
           {
361
           mCanRotate   = true;
362
           mCanDrag     = true;
363
           mCanUI       = true;
364

    
365
           if( i==BaseEffect.Type.SCRAMBLE.ordinal() )
366
             {
367
             final RubikActivity act = (RubikActivity)mView.getContext();
368

    
369
             act.runOnUiThread(new Runnable()
370
               {
371
               @Override
372
               public void run()
373
                 {
374
                 RubikState.switchState( act, RubikState.SOLV);
375
                 }
376
               });
377
             }
378
           break;
379
           }
380
         }
381
       }
382
     }
383

    
384
///////////////////////////////////////////////////////////////////////////////////////////////////
385

    
386
   public RubikObject getObject()
387
     {
388
     return mNewObject;
389
     }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

    
393
   public RubikObject getOldObject()
394
     {
395
     return mOldObject;
396
     }
397

    
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399

    
400
   public DistortedScreen getScreen()
401
     {
402
     return mScreen;
403
     }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
   public int getNumScrambles()
408
     {
409
     return mScrambleObjectNum;
410
     }
411
}
(2-2/3)