Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedRenderer.java @ e1637420

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.bandaged;
11

    
12
import java.io.File;
13
import java.io.FileNotFoundException;
14
import java.io.IOException;
15
import java.io.InputStream;
16
import java.nio.ByteBuffer;
17
import java.nio.ByteOrder;
18

    
19
import javax.microedition.khronos.egl.EGLConfig;
20
import javax.microedition.khronos.opengles.GL10;
21

    
22
import android.app.Activity;
23
import android.content.res.Resources;
24
import android.opengl.GLES31;
25
import android.opengl.GLSurfaceView;
26
import android.widget.Toast;
27

    
28
import org.distorted.dialogs.RubikDialogBandagedSave;
29
import org.distorted.library.effect.EffectType;
30
import org.distorted.library.effect.FragmentEffectBrightness;
31
import org.distorted.library.effect.PostprocessEffectBorder;
32
import org.distorted.library.main.DistortedEffects;
33
import org.distorted.library.main.DistortedFramebuffer;
34
import org.distorted.library.main.DistortedLibrary;
35
import org.distorted.library.main.DistortedNode;
36
import org.distorted.library.main.DistortedScreen;
37
import org.distorted.library.main.InternalOutputSurface;
38
import org.distorted.library.mesh.MeshBase;
39
import org.distorted.library.type.Static1D;
40
import org.distorted.library.type.Static3D;
41
import org.distorted.library.type.Static4D;
42
import org.distorted.objectlib.bandaged.BandagedObject;
43
import org.distorted.objectlib.bandaged.LocallyBandagedList;
44
import org.distorted.objectlib.json.JsonWriter;
45
import org.distorted.objectlib.main.ObjectControl;
46
import org.distorted.objectlib.main.TwistyObject;
47

    
48
import org.json.JSONException;
49

    
50
///////////////////////////////////////////////////////////////////////////////////////////////////
51

    
52
public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrary.LibraryUser
53
{
54
   public static final float BRIGHTNESS = 0.333f;
55
   private static final int RESET_DURATION = 1000;
56
   private static final float MAX_SIZE_CHANGE = 1.70f;
57
   private static final float MIN_SIZE_CHANGE = 0.50f;
58

    
59
   private final BandagedView mView;
60
   private final Resources mResources;
61
   private final DistortedScreen mScreen;
62
   private final Static3D mScale;
63
   private final Static4D mQuatT, mQuatA;
64
   private final BandagedObject mObject;
65
   private final float mInitRatio;
66

    
67
   private boolean mInitialPhase;
68
   private long mStartTime;
69
   private float mQuatX, mQuatY, mQuatZ, mQuatW;
70
   private boolean mResetQuats, mSetQuatT, mResettingObject, mConnectingCubits, mCreatingCubits, mRescaling;
71
   private int mIndex1, mIndex2;
72
   private int mSaveIcon;
73
   private DistortedFramebuffer mFramebuffer;
74
   private String mPath;
75
   private boolean mCubitsCreated;
76
   private int mWidth, mHeight;
77
   private float mScaleValue, mObjectScreenRatio;
78

    
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

    
81
   BandagedRenderer(BandagedView v, int ordinal)
82
     {
83
     mView = v;
84
     mResources = v.getResources();
85

    
86
     mQuatT = new Static4D(0,0,0,1);
87
     mQuatA = new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
88

    
89
     mResetQuats       = false;
90
     mSetQuatT         = false;
91
     mResettingObject  = false;
92
     mConnectingCubits = false;
93
     mCubitsCreated    = false;
94
     mCreatingCubits   = false;
95
     mRescaling        = false;
96

    
97
     mSaveIcon = -1;
98

    
99
     mScreen = new DistortedScreen();
100
     mScreen.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
101
     mScale = new Static3D(1,1,1);
102
     mObject= LocallyBandagedList.create(ordinal,mScreen);
103

    
104
     mInitRatio = mObject.getScreenRatio();
105
     mObjectScreenRatio= mInitRatio;
106
     }
107

    
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109

    
110
   @Override
111
   public void onDrawFrame(GL10 glUnused)
112
     {
113
     long time = System.currentTimeMillis();
114
     mScreen.render(time);
115

    
116
     if( mSetQuatT )
117
       {
118
       mSetQuatT = false;
119
       mQuatT.set(mQuatX,mQuatY,mQuatZ,mQuatW);
120
       }
121

    
122
     if( mResetQuats )
123
       {
124
       mResetQuats = false;
125

    
126
       float qx = mQuatT.get0();
127
       float qy = mQuatT.get1();
128
       float qz = mQuatT.get2();
129
       float qw = mQuatT.get3();
130

    
131
       float rx = mQuatA.get0();
132
       float ry = mQuatA.get1();
133
       float rz = mQuatA.get2();
134
       float rw = mQuatA.get3();
135

    
136
       float tx = rw*qx - rz*qy + ry*qz + rx*qw;
137
       float ty = rw*qy + rz*qx + ry*qw - rx*qz;
138
       float tz = rw*qz + rz*qw - ry*qx + rx*qy;
139
       float tw = rw*qw - rz*qz - ry*qy - rx*qx;
140

    
141
       mQuatT.set(0f, 0f, 0f, 1f);
142
       mQuatA.set(tx, ty, tz, tw);
143
       }
144

    
145
     if( mResettingObject )
146
       {
147
       boolean done = continueResetting(time);
148
       if( done ) mResettingObject = false;
149
       }
150

    
151
     if( mSaveIcon>=0 )
152
       {
153
       renderIcon(time); // for some reason we need to call render() twice here, otherwise the
154
       mSaveIcon++;      // icon turns out black. Probably some problem with binding the texture.
155
       }
156
     if( mSaveIcon>=2 )
157
       {
158
       saveIcon();
159
       mSaveIcon = -1;
160
       }
161

    
162
     if( mConnectingCubits )
163
       {
164
       mObject.tryConnectingCubits(mIndex1,mIndex2,mScaleValue);
165
       mConnectingCubits = false;
166
       }
167

    
168
     if( mCreatingCubits )
169
       {
170
       rescaleObject();
171

    
172
       if( mCubitsCreated )
173
         {
174
         mObject.createCubits(mQuatT,mQuatA,mScale);
175
         float[] dist = mObject.getDist3D();
176
         BandagedTouchControl control = mView.getTouchControl();
177
         control.setDist3D(dist);
178
         mScreen.detachAll();
179
         mView.resetCubits();
180
         mObject.attachCubits(mScaleValue);
181
         }
182

    
183
       mCreatingCubits = false;
184
       }
185

    
186
     if( mRescaling )
187
       {
188
       rescaleObject();
189
       mObject.scaleCubits(mScaleValue);
190
       BandagedTouchControl control = mView.getTouchControl();
191
       control.setObjectRatio(mObjectScreenRatio);
192
       mRescaling = false;
193
       }
194
     }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197

    
198
   @Override
199
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
200
      {
201
      if( width!=mWidth || height!=mHeight )
202
        {
203
        mWidth = width;
204
        mHeight= height;
205
        rescaleObject();
206
        mScreen.detachAll();
207
        int touched = mView.getTouched();
208
        mObject.attachAndMarkCubits(mScaleValue,touched);
209
        mView.setScreenSize(width,height);
210
        mScreen.resize(width,height);
211
        }
212
      }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
   @Override
217
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
218
      {
219
      DistortedLibrary.setMax(EffectType.VERTEX,0);
220
      MeshBase.setMaxEffComponents(ObjectControl.MAX_MOVING_PARTS);
221
      FragmentEffectBrightness.enable();
222
      DistortedLibrary.onSurfaceCreated(this,1);
223
      DistortedLibrary.setCull(true);
224
      mObject.recreateCubits(mQuatT,mQuatA,mScale);
225
      mCubitsCreated = true;
226
      mWidth = 0;
227
      mHeight= 0;
228
      }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231

    
232
   public DistortedScreen getScreen()
233
     {
234
     return mScreen;
235
     }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

    
239
   void setConnecting(int index1, int index2)
240
     {
241
     mIndex1 = index1;
242
     mIndex2 = index2;
243
     mConnectingCubits = true;
244
     }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

    
248
   public Static4D getQuatAccu()
249
     {
250
     return mQuatA;
251
     }
252

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

    
255
   public void setQuatTemp(float x, float y, float z, float w)
256
     {
257
     mSetQuatT = false;
258

    
259
     mQuatX = x;
260
     mQuatY = y;
261
     mQuatZ = z;
262
     mQuatW = w;
263

    
264
     mSetQuatT = true;
265
     }
266

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

    
269
   public void resetQuats()
270
     {
271
     mResetQuats = true;
272
     }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
   public boolean isBusy()
277
     {
278
     return (mResettingObject || mCreatingCubits || mConnectingCubits);
279
     }
280

    
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282

    
283
   public void saveObject()
284
     {
285
     TwistyObject obj = mObject.createObject(TwistyObject.MODE_NORM, 1.0f );
286
     String name = obj.getShortName();
287
     BandagedActivity act = (BandagedActivity) mView.getContext();
288

    
289
     if( act.objectDoesntExist(name) && createObjectJson(obj,act) )
290
       {
291
       setupIconCreation(act);
292
       act.addObject(obj.getShortName());
293
       act.doNotShowDialogAnymore();
294
       }
295
     }
296

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

    
299
   private boolean createObjectJson(TwistyObject object, Activity act)
300
     {
301
     final String name = object.getShortName()+"_object.json";
302
     File file = new File(act.getFilesDir(), name);
303
     String filename = file.getAbsolutePath();
304

    
305
     try
306
       {
307
       JsonWriter writer = JsonWriter.getInstance();
308
       String json = writer.createObjectString(object);
309
       writer.write(filename,json);
310
       return true;
311
       }
312
     catch(JSONException ex)
313
       {
314
       act.runOnUiThread(new Runnable()
315
         {
316
         public void run()
317
           {
318
           String message = "JSON Exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
319
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
320
           }
321
         });
322

    
323
       return false;
324
       }
325
     catch(FileNotFoundException ex)
326
       {
327
       act.runOnUiThread(new Runnable()
328
         {
329
         public void run()
330
           {
331
           String message = "FileNotFound exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
332
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
333
           }
334
         });
335

    
336
       return false;
337
       }
338
     catch(IOException ex)
339
       {
340
       act.runOnUiThread(new Runnable()
341
         {
342
         public void run()
343
           {
344
           String message = "IO exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
345
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
346
           }
347
         });
348

    
349
       return false;
350
       }
351
     }
352

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354

    
355
   private void setupIconCreation(Activity act)
356
     {
357
     final float R=1.0f;
358
     final int FBO_WIDTH  = (int)(R*720);
359
     final int FBO_HEIGHT = (int)(R*1280);
360
     final float OBJECT_SIZE = R*0.60f;
361

    
362
     TwistyObject obj = mObject.createObject(TwistyObject.MODE_ICON, OBJECT_SIZE );
363
     DistortedEffects effects = obj.getObjectEffects();
364
     DistortedNode node = obj.getNode();
365

    
366
     if( mFramebuffer==null )
367
       {
368
       mFramebuffer = new DistortedFramebuffer(FBO_WIDTH,FBO_HEIGHT,1, InternalOutputSurface.DEPTH_NO_STENCIL);
369
       mFramebuffer.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
370
       }
371

    
372
     mFramebuffer.setProjection( mObject.computeProjectionAngle() ,0.1f);
373
     mFramebuffer.detachAll();
374
     mFramebuffer.attach(node);
375

    
376
     Static1D halo = new Static1D(5);
377
     Static4D color = new Static4D(0,0,0,1);
378
     PostprocessEffectBorder border = new PostprocessEffectBorder(halo,color);
379
     border.setHaloDepth(false);
380
     effects.apply(border);
381

    
382
     final String name = obj.getShortName()+".png";
383
     File file = new File(act.getFilesDir(), name);
384
     String filename = file.getAbsolutePath();
385

    
386
     mSaveIcon = 0;
387
     mPath = filename;
388
     }
389

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

    
392
   private void renderIcon(long time)
393
     {
394
     mFramebuffer.render(time);
395
     }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398

    
399
   private void saveIcon()
400
     {
401
     int fW = mFramebuffer.getWidth();
402
     int fH = mFramebuffer.getHeight();
403

    
404
     ByteBuffer buf = ByteBuffer.allocateDirect(fW*fH*4);
405
     buf.order(ByteOrder.LITTLE_ENDIAN);
406

    
407
     mFramebuffer.setAsReadFramebuffer(0);
408
     GLES31.glReadBuffer(GLES31.GL_COLOR_ATTACHMENT0);
409
     GLES31.glReadPixels( 0, 0, fW, fH, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, buf);
410
     BandagedWorkerThread.newBuffer(buf,fW,fH,6,mPath);
411
     GLES31.glBindFramebuffer(GLES31.GL_READ_FRAMEBUFFER, 0);
412

    
413
     mSaveIcon = -1;
414
     }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
   void mulObjectRatio(float ratio)
419
     {
420
     mObjectScreenRatio *= ratio;
421

    
422
     if( mObjectScreenRatio>MAX_SIZE_CHANGE*mInitRatio) mObjectScreenRatio = MAX_SIZE_CHANGE*mInitRatio;
423
     if( mObjectScreenRatio<MIN_SIZE_CHANGE*mInitRatio) mObjectScreenRatio = MIN_SIZE_CHANGE*mInitRatio;
424

    
425
     mRescaling = true;
426
     }
427

    
428
///////////////////////////////////////////////////////////////////////////////////////////////////
429

    
430
   float getObjectRatio()
431
     {
432
     return mObjectScreenRatio;
433
     }
434

    
435
///////////////////////////////////////////////////////////////////////////////////////////////////
436

    
437
   private void rescaleObject()
438
     {
439
     float size = mObject.getMaxSize();
440
     final float Q = mObjectScreenRatio/size;
441
     mScaleValue = mWidth<mHeight ? Q*mWidth : Q*mHeight;
442
     mScale.set( mScaleValue,mScaleValue,mScaleValue );
443
     }
444

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

    
447
   public void changeObject(int x, int y, int z)
448
     {
449
     if( mObject.tryChangeObject(x,y,z) ) mCreatingCubits = true;
450
     }
451

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

    
454
   public void displaySavingDialog()
455
     {
456
     BandagedActivity act = (BandagedActivity)mView.getContext();
457
     RubikDialogBandagedSave saveDiag = new RubikDialogBandagedSave();
458
     saveDiag.show(act.getSupportFragmentManager(), null);
459
     }
460

    
461
///////////////////////////////////////////////////////////////////////////////////////////////////
462

    
463
   public void setupReset()
464
     {
465
     mResettingObject = true;
466
     mInitialPhase    = true;
467
     mStartTime       = System.currentTimeMillis();
468
     }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471

    
472
   public boolean continueResetting(long time)
473
     {
474
     long diff = time-mStartTime;
475
     float quotient = ((float)diff)/RESET_DURATION;
476

    
477
     if( mInitialPhase && quotient>0.5f )
478
       {
479
       mInitialPhase=false;
480
       mView.resetCubits();
481
       mObject.resetObject(mScaleValue);
482
       }
483

    
484
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
485

    
486
     float sinA = (float)Math.sin(angle);
487
     float cosA = (float)Math.cos(angle);
488

    
489
     mQuatT.set(0, -sinA, 0, cosA);
490

    
491
     return quotient>1.0f;
492
     }
493

    
494
///////////////////////////////////////////////////////////////////////////////////////////////////
495

    
496
  public void touchCubit(int index)
497
    {
498
    mObject.touchCubit(index);
499
    }
500

    
501
///////////////////////////////////////////////////////////////////////////////////////////////////
502

    
503
  public void untouchCubit(int index)
504
    {
505
    mObject.untouchCubit(index);
506
    }
507

    
508
///////////////////////////////////////////////////////////////////////////////////////////////////
509

    
510
  public BandagedTouchControl createTouchControl()
511
    {
512
    return new BandagedTouchControl( getObjectRatio() , mScreen.getFOV(), mObject );
513
    }
514

    
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516

    
517
  public void distortedException(Exception ex)
518
    {
519
    android.util.Log.e("BandagedCreator", "unexpected exception: "+ex.getMessage() );
520
    }
521

    
522
///////////////////////////////////////////////////////////////////////////////////////////////////
523

    
524
  public InputStream localFile(int fileID)
525
    {
526
    return mResources.openRawResource(fileID);
527
    }
528

    
529
///////////////////////////////////////////////////////////////////////////////////////////////////
530

    
531
  public void logMessage(String message)
532
    {
533
    android.util.Log.e("BandagedCreator", message );
534
    }
535
}
(3-3/7)