Project

General

Profile

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

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

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.AppearEffect;
25
import org.distorted.effect.DisappearEffect;
26
import org.distorted.library.effect.VertexEffectSink;
27
import org.distorted.library.main.DistortedEffects;
28
import org.distorted.library.main.DistortedLibrary;
29
import org.distorted.library.main.DistortedScreen;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshQuad;
32
import org.distorted.library.message.EffectListener;
33
import org.distorted.library.message.EffectMessage;
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;
53
    private long mRotationFinishedID, mDisappearEffectID, mAppearEffectID;
54
    private boolean mFinishRotation, mRemoveRotation, mFinishDragCurrent, mFinishDragAccumulated;
55
    private boolean mCanRotate, mCanDrag;
56
    private RubikCube mOldCube, mNewCube;
57
    private int mScreenWidth, mScreenHeight;
58
    private MeshQuad mMesh;
59
    private AppearEffect.Type mAppearType;
60
    private DisappearEffect.Type mDisappearType;
61
    private int mAppearDuration, mDisappearDuration;
62

    
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64

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

    
69
      mScreen = new DistortedScreen();
70

    
71
      mOldCube = null;
72
      mNewCube = null;
73

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

    
79
      mScreenWidth = mScreenHeight = 0;
80

    
81
      mFinishRotation        = false;
82
      mRemoveRotation        = false;
83
      mFinishDragCurrent     = false;
84
      mFinishDragAccumulated = false;
85

    
86
      mCanRotate = true;
87
      mCanDrag   = true;
88

    
89
      mAppearType    = AppearEffect.Type.SCALE;
90
      mDisappearType = DisappearEffect.Type.SCALE;
91

    
92
      mAppearDuration    = 1000;
93
      mDisappearDuration = 1000;
94

    
95
      mMesh= new MeshQuad();
96
      mNextCubeSize =RubikActivity.getSize();
97
      }
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100
// various things are done here delayed, 'after the next render' as not to be done mid-render and
101
// cause artifacts.
102

    
103
    @Override
104
    public void onDrawFrame(GL10 glUnused) 
105
      {
106
      mScreen.render( System.currentTimeMillis() );
107

    
108
      if( mFinishDragCurrent )
109
        {
110
        mFinishDragCurrent = false;
111
        mQuatCurrent.set(mTempCurrent);
112
        }
113

    
114
      if( mFinishDragAccumulated )
115
        {
116
        mFinishDragAccumulated = false;
117
        mQuatAccumulated.set(mTempAccumulated);
118
        }
119

    
120
      if( mFinishRotation )
121
        {
122
        mCanRotate = false;
123
        mFinishRotation=false;
124
        mRotationFinishedID = mNewCube.finishRotationNow(this);
125
        }
126

    
127
      if( mRemoveRotation )
128
        {
129
        mRemoveRotation=false;
130
        mNewCube.removeRotationNow(this);
131
        mCanRotate = true;
132
        }
133

    
134
      if( mNextCubeSize!=0 )
135
        {
136
        createCubeNow(mNextCubeSize);
137

    
138
        mCanDrag   = false;
139
        mCanRotate = false;
140
        mNextCubeSize = 0;
141

    
142
        if( mOldCube!=null ) disappearCube();
143
        else                    appearCube();
144
        }
145
      }
146

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

    
149
   @Override
150
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
151
      {
152
      if( mNewCube!=null ) mNewCube.createTexture();
153

    
154
      float cameraDistance = CAMERA_DISTANCE*(width>height ? width:height);
155
      float fovInDegrees   = computeFOV(cameraDistance,height);
156

    
157
      mScreen.setProjection( fovInDegrees, 0.1f);
158
      mView.setScreenSize(width,height);
159
      mView.setCameraDist(cameraDistance);
160
      mScreen.resize(width, height);
161

    
162
      recomputeScaleFactor(width,height);
163

    
164
      mScreenHeight = height;
165
      mScreenWidth  = width;
166
      }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

    
170
   @Override
171
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
172
      {
173
      VertexEffectSink.enable();
174
      AppearEffect.enableEffects();
175
      DisappearEffect.enableEffects();
176

    
177
      try
178
        {
179
        DistortedLibrary.onCreate(mView.getContext());
180
        }
181
      catch(Exception ex)
182
        {
183
        android.util.Log.e("Rubik", ex.getMessage() );
184
        }
185
      }
186

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

    
189
   public void effectMessage(final EffectMessage em, final long effectID, final long objectID)
190
     {
191
     if(      effectID == mRotationFinishedID )
192
       {
193
       mRemoveRotation = true;
194
       }
195
     else if( effectID == mDisappearEffectID )
196
       {
197
       appearCube();
198
       }
199
     else if( effectID == mAppearEffectID    )
200
       {
201
       mCanRotate = true;
202
       mCanDrag   = true;
203
       }
204
     }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

    
208
   private void disappearCube()
209
     {
210
     try
211
       {
212
       DisappearEffect effect = DisappearEffect.create(mDisappearType);
213
       mDisappearEffectID = effect.start(mDisappearDuration,mScreen,mOldCube,this);
214
       }
215
     catch(Exception ex)
216
       {
217
       android.util.Log.e("Renderer", "failed to create DisappearEffect, exception: "+ex.getMessage());
218
       }
219
     }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222

    
223
   private void appearCube()
224
     {
225
     try
226
       {
227
       AppearEffect effect = AppearEffect.create(mAppearType);
228
       mAppearEffectID = effect.start(mAppearDuration,mScreen,mNewCube,this);
229
       }
230
     catch(Exception ex)
231
       {
232
       android.util.Log.e("Renderer", "failed to create AppearEffect, exception: "+ex.getMessage());
233

    
234
       mScreen.attach(mNewCube); //
235
       mCanRotate = true;        // just appear the cube
236
       mCanDrag   = true;        //
237
       }
238
     }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
   private float computeFOV(float cameraDistance, int screenHeight)
243
     {
244
     double halfFOVInRadians = Math.atan( screenHeight/(2*cameraDistance) );
245
     return (float)(2*halfFOVInRadians*(180/Math.PI));
246
     }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249
// no this will not race with onDrawFrame
250

    
251
   void finishRotation()
252
     {
253
     mFinishRotation = true;
254
     }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257

    
258
   void setAppearDuration(int duration)
259
     {
260
     mAppearDuration = duration;
261
     }
262

    
263
///////////////////////////////////////////////////////////////////////////////////////////////////
264

    
265
   void setDisappearDuration(int duration)
266
     {
267
     mDisappearDuration = duration;
268
     }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
   void setAppearType(AppearEffect.Type type)
273
     {
274
     mAppearType = type;
275
     }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
   void setDisappearType(DisappearEffect.Type type)
280
     {
281
     mDisappearType = type;
282
     }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285

    
286
   boolean createCube(int newSize)
287
     {
288
     if( mCanDrag && mCanRotate && (mNewCube==null || newSize != mNewCube.getSize()) )
289
       {
290
       mNextCubeSize = newSize;
291
       return true;
292
       }
293

    
294
     return false;
295
     }
296

    
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298

    
299
   private void createCubeNow(int newSize)
300
     {
301
     if( mOldCube!=null ) mOldCube.releaseResources();
302
     mOldCube = mNewCube;
303

    
304
     DistortedTexture texture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
305
     DistortedEffects effects = new DistortedEffects();
306

    
307
     mNewCube = new RubikCube(newSize, mQuatCurrent, mQuatAccumulated, texture, mMesh, effects);
308
     mNewCube.createTexture();
309

    
310
     if( mScreenWidth!=0 )
311
       {
312
       recomputeScaleFactor(mScreenWidth,mScreenHeight);
313
       }
314
     }
315

    
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317

    
318
   private void recomputeScaleFactor(int screenWidth, int screenHeight)
319
     {
320
     mCubeSizeInScreenSpace = CUBE_SCREEN_RATIO*(screenWidth>screenHeight ? screenHeight:screenWidth);
321

    
322
     if( mNewCube!=null )
323
       {
324
       mNewCube.recomputeScaleFactor(screenWidth, screenHeight, mCubeSizeInScreenSpace);
325
       }
326
     }
327

    
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329

    
330
   void scrambleCube()
331
     {
332

    
333
     }
334

    
335
///////////////////////////////////////////////////////////////////////////////////////////////////
336

    
337
   float returnCubeSizeInScreenSpace()
338
     {
339
     return mCubeSizeInScreenSpace;
340
     }
341

    
342
///////////////////////////////////////////////////////////////////////////////////////////////////
343

    
344
   boolean canRotate()
345
     {
346
     return mCanRotate;
347
     }
348

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

    
351
   boolean canDrag()
352
     {
353
     return mCanDrag;
354
     }
355

    
356
///////////////////////////////////////////////////////////////////////////////////////////////////
357

    
358
   RubikCube getCube()
359
     {
360
     return mNewCube;
361
     }
362

    
363
///////////////////////////////////////////////////////////////////////////////////////////////////
364
// Initial rotation of the cube. Something semi-random that looks good.
365

    
366
   Static4D initializeQuat()
367
     {
368
     return new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
369
     }
370

    
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372

    
373
   void setQuatCurrent(Static4D current)
374
     {
375
     mTempCurrent.set(current);
376
     mFinishDragCurrent = true;
377
     }
378

    
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380

    
381
   void setQuatAccumulated(Static4D accumulated)
382
     {
383
     mTempAccumulated.set(accumulated);
384
     mFinishDragAccumulated = true;
385
     }
386
}
(3-3/4)