Project

General

Profile

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

magiccube / src / main / java / org / distorted / magic / RubikRenderer.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.opengl.GLSurfaceView;
23

    
24
import org.distorted.effect.SizeChangeEffect;
25
import org.distorted.effect.SolveEffect;
26
import org.distorted.effect.ScrambleEffect;
27
import org.distorted.library.effect.VertexEffectSink;
28
import org.distorted.library.main.DistortedEffects;
29
import org.distorted.library.main.DistortedLibrary;
30
import org.distorted.library.main.DistortedScreen;
31
import org.distorted.library.main.DistortedTexture;
32
import org.distorted.library.mesh.MeshFlat;
33
import org.distorted.library.message.EffectListener;
34
import org.distorted.library.type.Static4D;
35

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

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

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

    
47
    private RubikSurfaceView mView;
48
    private DistortedScreen mScreen;
49
    private Static4D mQuatCurrent, mQuatAccumulated;
50
    private Static4D mTempCurrent, mTempAccumulated;
51
    private float mCubeSizeInScreenSpace;
52
    private int mNextCubeSize, mScrambleCubeNum;
53
    private long mRotationFinishedID, mSizeChangeEffectID, mSolveEffectID, mScrambleEffectID;
54
    private boolean mFinishRotation, mRemoveRotation, mFinishDragCurrent, mFinishDragAccumulated, mSolveCube, mScrambleCube;
55
    private boolean mCanRotate, mCanDrag, mCanScramble, mCanSolve;
56
    private RubikCube mOldCube, mNewCube;
57
    private int mScreenWidth, mScreenHeight;
58
    private MeshFlat mMesh;
59
    private int[] mPos;
60
    private int[] mType;
61

    
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63

    
64
    RubikRenderer(RubikSurfaceView v)
65
      {
66
      mView = v;
67

    
68
      mScreen = new DistortedScreen();
69

    
70
      mOldCube = null;
71
      mNewCube = null;
72

    
73
      mTempCurrent     = new Static4D(0,0,0,1);
74
      mTempAccumulated = new Static4D(0,0,0,1);
75
      mQuatCurrent     = new Static4D(0,0,0,1);
76
      mQuatAccumulated = new Static4D(0,0,0,1);
77

    
78
      mScreenWidth = mScreenHeight = 0;
79
      mScrambleCubeNum = 0;
80

    
81
      mFinishRotation        = false;
82
      mRemoveRotation        = false;
83
      mFinishDragCurrent     = false;
84
      mFinishDragAccumulated = false;
85
      mSolveCube             = false;
86
      mScrambleCube          = false;
87

    
88
      mCanRotate   = true;
89
      mCanDrag     = true;
90
      mCanScramble = true;
91
      mCanSolve    = true;
92

    
93
      mPos  = new int[RubikSettingsEnum.LENGTH];
94
      mType = new int[RubikSettingsEnum.LENGTH];
95

    
96
      for (int i=0; i<RubikSettingsEnum.LENGTH; i++)
97
        {
98
        mPos[i] = 1000;
99
        }
100

    
101
      mMesh= new MeshFlat(20,20);
102
      mNextCubeSize =RubikActivity.getSize();
103
      }
104

    
105
///////////////////////////////////////////////////////////////////////////////////////////////////
106
// various things are done here delayed, 'after the next render' as not to be done mid-render and
107
// cause artifacts.
108

    
109
    @Override
110
    public void onDrawFrame(GL10 glUnused) 
111
      {
112
      mScreen.render( System.currentTimeMillis() );
113

    
114
      if( mFinishDragCurrent )
115
        {
116
        mFinishDragCurrent = false;
117
        mQuatCurrent.set(mTempCurrent);
118
        }
119

    
120
      if( mFinishDragAccumulated )
121
        {
122
        mFinishDragAccumulated = false;
123
        mQuatAccumulated.set(mTempAccumulated);
124
        }
125

    
126
      if( mFinishRotation )
127
        {
128
        mCanRotate = false;
129
        mFinishRotation=false;
130
        mRotationFinishedID = mNewCube.finishRotationNow(this);
131
        }
132

    
133
      if( mRemoveRotation )
134
        {
135
        mRemoveRotation=false;
136
        mNewCube.removeRotationNow();
137
        mCanRotate = true;
138
        }
139

    
140
      if( mNextCubeSize!=0 )
141
        {
142
        createCubeNow(mNextCubeSize);
143

    
144
        mCanDrag   = false;
145
        mCanRotate = false;
146
        mNextCubeSize = 0;
147

    
148
        sizeChangeEffect();
149
        }
150

    
151
      if( mSolveCube )
152
        {
153
        mSolveCube   = false;
154
        mCanDrag     = false;
155
        mCanRotate   = false;
156
        mCanScramble = false;
157
        mCanSolve    = false;
158
        solveCubeNow();
159
        }
160

    
161
      if( mScrambleCube )
162
        {
163
        mScrambleCube = false;
164
        mCanDrag      = false;
165
        mCanRotate    = false;
166
        mCanScramble  = false;
167
        mCanSolve     = false;
168
        scrambleCubeNow();
169
        }
170
      }
171

    
172
///////////////////////////////////////////////////////////////////////////////////////////////////
173

    
174
   @Override
175
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
176
      {
177
      if( mNewCube!=null ) mNewCube.createTexture();
178

    
179
      float cameraDistance = CAMERA_DISTANCE*(width>height ? width:height);
180
      float fovInDegrees   = computeFOV(cameraDistance,height);
181

    
182
      mScreen.setProjection( fovInDegrees, 0.1f);
183
      mView.setScreenSize(width,height);
184
      mView.setCameraDist(cameraDistance);
185
      mScreen.resize(width, height);
186

    
187
      recomputeScaleFactor(width,height);
188

    
189
      mScreenHeight = height;
190
      mScreenWidth  = width;
191
      }
192

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

    
195
   @Override
196
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
197
      {
198
      VertexEffectSink.enable();
199
      SizeChangeEffect.enableEffects();
200
      ScrambleEffect.enableEffects();
201
      SolveEffect.enableEffects();
202

    
203
      try
204
        {
205
        DistortedLibrary.onCreate(mView.getContext());
206
        }
207
      catch(Exception ex)
208
        {
209
        android.util.Log.e("Rubik", ex.getMessage() );
210
        }
211
      }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
   public void effectFinished(final long effectID)
216
     {
217
     if(      effectID == mRotationFinishedID )
218
       {
219
       mRemoveRotation = true;
220
       }
221
     else if( effectID == mSizeChangeEffectID )
222
       {
223
       mCanRotate   = true;
224
       mCanDrag     = true;
225
       }
226
     else if( effectID == mSolveEffectID )
227
       {
228
       mCanRotate   = true;
229
       mCanDrag     = true;
230
       mCanSolve    = true;
231
       mCanScramble = true;
232
       }
233
     else if( effectID == mScrambleEffectID   )
234
       {
235
       mCanRotate   = true;
236
       mCanDrag     = true;
237
       mCanSolve    = true;
238
       mCanScramble = true;
239
       }
240
     }
241

    
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243

    
244
   private void sizeChangeEffect()
245
     {
246
     try
247
       {
248
       SizeChangeEffect effect = SizeChangeEffect.create(mType[0]);
249
       mSizeChangeEffectID = effect.start(mPos[0],mScreen,mOldCube,mNewCube,this);
250
       }
251
     catch(Exception ex)
252
       {
253
       android.util.Log.e("Renderer", "failed to create SizeChangeEffect, exception: "+ex.getMessage());
254

    
255
       if( mOldCube!=null ) mScreen.detach(mOldCube);
256
       mScreen.attach(mNewCube);
257
       mCanRotate = true;
258
       mCanDrag   = true;
259
       }
260
     }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

    
264
   private float computeFOV(float cameraDistance, int screenHeight)
265
     {
266
     double halfFOVInRadians = Math.atan( screenHeight/(2*cameraDistance) );
267
     return (float)(2*halfFOVInRadians*(180/Math.PI));
268
     }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271
// no this will not race with onDrawFrame
272

    
273
   void finishRotation()
274
     {
275
     mFinishRotation = true;
276
     }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
   void setPos(int index, int pos)
281
     {
282
     if( index>=0 && index<RubikSettingsEnum.LENGTH )  mPos[index] = pos;
283
     }
284

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

    
287
   void setType(int index, int type)
288
     {
289
     if( index>=0 && index<RubikSettingsEnum.LENGTH )  mType[index] = type;
290
     }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
   boolean createCube(int newSize)
295
     {
296
     if( mCanDrag && mCanRotate && (mNewCube==null || newSize != mNewCube.getSize()) )
297
       {
298
       mNextCubeSize = newSize;
299
       return true;
300
       }
301

    
302
     return false;
303
     }
304

    
305
///////////////////////////////////////////////////////////////////////////////////////////////////
306

    
307
   private void createCubeNow(int newSize)
308
     {
309
     if( mOldCube!=null ) mOldCube.releaseResources();
310
     mOldCube = mNewCube;
311

    
312
     DistortedTexture texture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
313
     DistortedEffects effects = new DistortedEffects();
314

    
315
     mNewCube = new RubikCube(newSize, mQuatCurrent, mQuatAccumulated, texture, mMesh, effects);
316
     mNewCube.createTexture();
317

    
318
     if( mScreenWidth!=0 )
319
       {
320
       recomputeScaleFactor(mScreenWidth,mScreenHeight);
321
       }
322
     }
323

    
324
///////////////////////////////////////////////////////////////////////////////////////////////////
325

    
326
   private void recomputeScaleFactor(int screenWidth, int screenHeight)
327
     {
328
     mCubeSizeInScreenSpace = CUBE_SCREEN_RATIO*(screenWidth>screenHeight ? screenHeight:screenWidth);
329

    
330
     if( mNewCube!=null )
331
       {
332
       mNewCube.recomputeScaleFactor(screenWidth, screenHeight, mCubeSizeInScreenSpace);
333
       }
334
     }
335

    
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

    
338
   void scrambleCube(int num)
339
     {
340
     if( mCanScramble )
341
       {
342
       mScrambleCube = true;
343
       mScrambleCubeNum = num;
344
       }
345
     }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

    
349
   private void scrambleCubeNow()
350
     {
351
     try
352
       {
353
       ScrambleEffect effect = ScrambleEffect.create(mType[2]);
354
       mScrambleEffectID = effect.start(mPos[2],mNewCube,mScrambleCubeNum,this);
355
       }
356
     catch(Exception ex)
357
       {
358
       android.util.Log.e("Renderer", "failed to create ScrambleEffect, exception: "+ex.getMessage());
359

    
360
       mCanRotate = true;
361
       mCanDrag   = true;
362
       }
363
     }
364

    
365
///////////////////////////////////////////////////////////////////////////////////////////////////
366

    
367
   void solveCube()
368
     {
369
     if( mCanSolve )
370
       {
371
       mSolveCube = true;
372
       }
373
     }
374

    
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376

    
377
   private void solveCubeNow()
378
     {
379
     try
380
       {
381
       SolveEffect effect = SolveEffect.create(mType[1]);
382
       mSolveEffectID = effect.start(mPos[1],mScreen,mNewCube,this);
383
       }
384
     catch(Exception ex)
385
       {
386
       android.util.Log.e("Renderer", "failed to create SolveEffect, exception: "+ex.getMessage());
387

    
388
       mNewCube.solve();    //
389
       mCanRotate = true;   // just solve the cube
390
       mCanDrag   = true;   //
391
       }
392
     }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

    
396
   float returnCubeSizeInScreenSpace()
397
     {
398
     return mCubeSizeInScreenSpace;
399
     }
400

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402

    
403
   boolean canRotate()
404
     {
405
     return mCanRotate;
406
     }
407

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

    
410
   boolean canDrag()
411
     {
412
     return mCanDrag;
413
     }
414

    
415
///////////////////////////////////////////////////////////////////////////////////////////////////
416

    
417
   RubikCube getCube()
418
     {
419
     return mNewCube;
420
     }
421

    
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423

    
424
   void setQuatCurrent(Static4D current)
425
     {
426
     mTempCurrent.set(current);
427
     mFinishDragCurrent = true;
428
     }
429

    
430
///////////////////////////////////////////////////////////////////////////////////////////////////
431

    
432
   void setQuatAccumulated(Static4D accumulated)
433
     {
434
     mTempAccumulated.set(accumulated);
435
     mFinishDragAccumulated = true;
436
     }
437
}
(4-4/7)