Project

General

Profile

Download (9.62 KB) Statistics
| Branch: | Revision:

examples / src / main / java / org / distorted / examples / rubik / RubikRenderer.java @ 96ddd33a

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.examples.rubik;
21

    
22
import android.opengl.GLSurfaceView;
23

    
24
import org.distorted.library.effect.VertexEffectSink;
25
import org.distorted.library.main.Distorted;
26
import org.distorted.library.main.DistortedScreen;
27
import org.distorted.library.message.EffectListener;
28
import org.distorted.library.message.EffectMessage;
29
import org.distorted.library.type.Static3D;
30
import org.distorted.library.type.Static4D;
31

    
32
import javax.microedition.khronos.egl.EGLConfig;
33
import javax.microedition.khronos.opengles.GL10;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36

    
37
class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
38
{
39
    private static final float CUBE_SCREEN_RATIO = 0.5f;
40
    private static final float CAMERA_DISTANCE   = 0.6f;  // 0.6 of the length of max(scrHeight,scrWidth)
41

    
42
    private RubikSurfaceView mView;
43
    private DistortedScreen mScreen;
44
    private Static3D mMove, mScale;
45
    private Static4D mQuatCurrent, mQuatAccumulated;
46
    private Static4D mTempCurrent, mTempAccumulated;
47
    private float mCubeSizeInScreenSpace;
48
    private int mNextCubeSize;
49
    private boolean mFinishRotation, mRemoveRotation, mFinishDragCurrent, mFinishDragAccumulated;
50
    private boolean mCanRotate;
51
    private RubikCube mCube;
52

    
53
    private int mScreenWidth, mScreenHeight;
54

    
55
///////////////////////////////////////////////////////////////////////////////////////////////////
56

    
57
    RubikRenderer(RubikSurfaceView v)
58
      {
59
      mView = v;
60

    
61
      mScreen = new DistortedScreen();
62

    
63
      mTempCurrent     = new Static4D(0,0,0,1);
64
      mTempAccumulated = initializeQuat();
65
      mQuatCurrent     = new Static4D(0,0,0,1);
66
      mQuatAccumulated = initializeQuat();
67

    
68
      mScreenWidth = mScreenHeight = 0;
69

    
70
      mMove  = new Static3D(0,0,0);
71
      mScale = new Static3D(1,1,1);
72

    
73
      mFinishRotation        = false;
74
      mRemoveRotation        = false;
75
      mFinishDragCurrent     = false;
76
      mFinishDragAccumulated = false;
77

    
78
      mNextCubeSize= 0;
79

    
80
      mCanRotate = true;
81
      }
82

    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
// various things are done here delayed, 'after the next render' as not to be done mid-render and
85
// cause artifacts.
86

    
87
    public void onDrawFrame(GL10 glUnused) 
88
      {
89
      mScreen.render( System.currentTimeMillis() );
90

    
91
      if( mFinishDragCurrent )
92
        {
93
        mFinishDragCurrent = false;
94
        mQuatCurrent.set(mTempCurrent);
95
        }
96

    
97
      if( mFinishDragAccumulated )
98
        {
99
        mFinishDragAccumulated = false;
100
        mQuatAccumulated.set(mTempAccumulated);
101
        }
102

    
103
      if( mFinishRotation )
104
        {
105
        mCanRotate = false;
106
        mFinishRotation=false;
107
        mCube.finishRotationNow(this);
108
        }
109

    
110
      if( mRemoveRotation )
111
        {
112
        mRemoveRotation=false;
113
        mCube.removeRotationNow(this);
114
        mCanRotate = true;
115
        }
116

    
117
      if( mNextCubeSize!=0 )
118
        {
119
        createCubeNow(mNextCubeSize);
120
        mScreen.detachAll();
121
        mCube.attachToScreen(mScreen);
122
        mNextCubeSize = 0;
123
        mCanRotate = true;   // it can happen that we have just changed the size of the cube while
124
                             // finishing rotation and never removed it!
125
        }
126
      }
127

    
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
// EffectListener. The library sends a message to us when it's time to call 'removeRotation'
130

    
131
   public void effectMessage(final EffectMessage em, final long effectID, final long objectID)
132
     {
133
     switch(em)
134
        {
135
        case EFFECT_FINISHED: mRemoveRotation = true; break;
136
        }
137
     }
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140
    
141
    public void onSurfaceChanged(GL10 glUnused, int width, int height) 
142
      {
143
      float cameraDistance = CAMERA_DISTANCE*(width>height ? width:height);
144
      float fovInDegrees   = computeFOV(cameraDistance,height);
145

    
146
      mScreen.setProjection( fovInDegrees, 0.1f);
147
      mView.setScreenSize(width,height);
148
      mView.setCameraDist(cameraDistance);
149
      mScreen.resize(width, height);
150

    
151
      recomputeScaleFactor(width,height);
152

    
153
      mScreenHeight = height;
154
      mScreenWidth  = width;
155
      }
156

    
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158
    
159
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
160
      {
161
      mCube.createTexture();
162
      mScreen.detachAll();
163
      mCube.attachToScreen(mScreen);
164

    
165
      VertexEffectSink.enable();
166

    
167
      try
168
        {
169
        Distorted.onCreate(mView.getContext());
170
        }
171
      catch(Exception ex)
172
        {
173
        android.util.Log.e("Rubik", ex.getMessage() );
174
        }
175
      }
176

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

    
179
   private float computeFOV(float cameraDistance, int screenHeight)
180
     {
181
     double halfFOVInRadians = Math.atan( screenHeight/(2*cameraDistance) );
182
     return (float)(2*halfFOVInRadians*(180/Math.PI));
183
     }
184

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186
// no this will not race with onDrawFrame
187

    
188
   void finishRotation()
189
     {
190
     mFinishRotation = true;
191
     }
192

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

    
195
   void createCube(int newSize)
196
     {
197
     mNextCubeSize = newSize;
198
     }
199

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201

    
202
   void createCubeNow(int newSize)
203
     {
204
     int oldSize = mCube==null ? 0 : mCube.getSize();
205

    
206
     if( oldSize!=newSize )
207
       {
208
       if( mCube!=null ) mCube.releaseResources();
209
       mCube = new RubikCube(newSize, mMove, mScale, mQuatCurrent, mQuatAccumulated);
210
       mCube.createTexture();
211

    
212
       if( mScreenWidth!=0 )
213
         {
214
         recomputeScaleFactor(mScreenWidth,mScreenHeight);
215
         }
216
       }
217
     }
218

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

    
221
   private void recomputeScaleFactor(int screenWidth, int screenHeight)
222
     {
223
     mCubeSizeInScreenSpace = CUBE_SCREEN_RATIO*(screenWidth>screenHeight ? screenHeight:screenWidth);
224
     float texSize = mCube.getTextureSize();
225
     float scaleFactor = mCubeSizeInScreenSpace/(texSize*mCube.getSize());
226

    
227
     mMove.set( (screenWidth-scaleFactor*texSize)/2 , (screenHeight-scaleFactor*texSize)/2 , -scaleFactor*texSize/2 );
228
     mScale.set(scaleFactor,scaleFactor,scaleFactor);
229
     }
230

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

    
233
   void scrambleCube()
234
     {
235

    
236
     }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

    
240
   float returnCubeSizeInScreenSpace()
241
     {
242
     return mCubeSizeInScreenSpace;
243
     }
244

    
245
///////////////////////////////////////////////////////////////////////////////////////////////////
246

    
247
   boolean canRotate()
248
     {
249
     return mCanRotate;
250
     }
251

    
252
///////////////////////////////////////////////////////////////////////////////////////////////////
253

    
254
   RubikCube getCube()
255
     {
256
     return mCube;
257
     }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260
// Initial rotation of the cube. Something semi-random that looks good.
261

    
262
   Static4D initializeQuat()
263
     {
264
     return new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
265
     }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

    
269
   void setQuatCurrent(Static4D current)
270
     {
271
     mTempCurrent.set(current);
272
     mFinishDragCurrent = true;
273
     }
274

    
275
///////////////////////////////////////////////////////////////////////////////////////////////////
276

    
277
   void setQuatAccumulated(Static4D accumulated)
278
     {
279
     mTempAccumulated.set(accumulated);
280
     mFinishDragAccumulated = true;
281
     }
282
}
(3-3/4)