Project

General

Profile

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

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

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 org.json.JSONException;
13

    
14
import java.io.File;
15
import java.io.FileNotFoundException;
16
import java.io.IOException;
17
import java.io.InputStream;
18
import java.nio.ByteBuffer;
19
import java.nio.ByteOrder;
20
import java.util.Stack;
21

    
22
import javax.microedition.khronos.egl.EGLConfig;
23
import javax.microedition.khronos.opengles.GL10;
24

    
25
import android.app.Activity;
26
import android.content.res.Resources;
27
import android.opengl.GLES31;
28
import android.opengl.GLSurfaceView;
29
import android.widget.Toast;
30

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

    
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52

    
53
public class BandagedRenderer implements GLSurfaceView.Renderer, DistortedLibrary.LibraryUser
54
{
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;
71
   private boolean mCreatingCubits, mRescaling, mUndoingObject;
72
   private int mIndex1, mIndex2;
73
   private int mSaveIcon;
74
   private DistortedFramebuffer mFramebuffer;
75
   private String mPath;
76
   private boolean mCubitsCreated;
77
   private int mWidth, mHeight;
78
   private float mScaleValue, mObjectScreenRatio;
79

    
80
   private final Stack<Integer> mPairs;  // each Integer holds a packed pair in ints
81

    
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83

    
84
   BandagedRenderer(BandagedView v, int ordinal)
85
     {
86
     mView = v;
87
     mResources = v.getResources();
88

    
89
     mQuatT = new Static4D(0,0,0,1);
90
     mQuatA = new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
91

    
92
     mResetQuats       = false;
93
     mSetQuatT         = false;
94
     mResettingObject  = false;
95
     mConnectingCubits = false;
96
     mCubitsCreated    = false;
97
     mCreatingCubits   = false;
98
     mRescaling        = false;
99
     mUndoingObject    = false;
100

    
101
     mSaveIcon = -1;
102

    
103
     mScreen = new DistortedScreen();
104

    
105
     BandagedActivity act = (BandagedActivity)v.getContext();
106
     act.setUpBackgroundColor(mScreen);
107

    
108
     mScale = new Static3D(1,1,1);
109
     mObject= LocallyBandagedList.create(ordinal,mScreen);
110

    
111
     mInitRatio = mObject.getScreenRatio();
112
     mObjectScreenRatio= mInitRatio;
113

    
114
     mPairs = new Stack<>();
115
     }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

    
119
   @Override
120
   public void onDrawFrame(GL10 glUnused)
121
     {
122
     long time = System.currentTimeMillis();
123
     mScreen.render(time);
124

    
125
     if( mSetQuatT )
126
       {
127
       mSetQuatT = false;
128
       mQuatT.set(mQuatX,mQuatY,mQuatZ,mQuatW);
129
       }
130

    
131
     if( mResetQuats )
132
       {
133
       mResetQuats = false;
134

    
135
       float qx = mQuatT.get0();
136
       float qy = mQuatT.get1();
137
       float qz = mQuatT.get2();
138
       float qw = mQuatT.get3();
139

    
140
       float rx = mQuatA.get0();
141
       float ry = mQuatA.get1();
142
       float rz = mQuatA.get2();
143
       float rw = mQuatA.get3();
144

    
145
       float tx = rw*qx - rz*qy + ry*qz + rx*qw;
146
       float ty = rw*qy + rz*qx + ry*qw - rx*qz;
147
       float tz = rw*qz + rz*qw - ry*qx + rx*qy;
148
       float tw = rw*qw - rz*qz - ry*qy - rx*qx;
149

    
150
       mQuatT.set(0f, 0f, 0f, 1f);
151
       mQuatA.set(tx, ty, tz, tw);
152
       }
153

    
154
     if( mResettingObject )
155
       {
156
       boolean done = continueResetting(time);
157
       if( done )
158
         {
159
         mResettingObject = false;
160
         mPairs.clear();
161
         }
162
       }
163

    
164
     if( mSaveIcon>=0 )
165
       {
166
       renderIcon(time); // for some reason we need to call render() twice here, otherwise the
167
       mSaveIcon++;      // icon turns out black. Probably some problem with binding the texture.
168
       }
169
     if( mSaveIcon>=2 )
170
       {
171
       saveIcon();
172
       mSaveIcon = -1;
173
       }
174

    
175
     if( mConnectingCubits )
176
       {
177
       boolean success = mObject.tryConnectingCubits(mIndex1,mIndex2,mScaleValue);
178
       if( success ) mPairs.add( packTwoIntsIntoPair(mIndex1,mIndex2) );
179
       mConnectingCubits = false;
180
       }
181
     if( mUndoingObject )
182
       {
183
       int num = mPairs.size();
184

    
185
       if( num>0 )
186
         {
187
         int pair  = mPairs.pop();
188
         int first = getFirstFromPair(pair);
189
         int second= getSecondFromPair(pair);
190
         mObject.disconnectCubits(first, second, mScaleValue);
191
         }
192

    
193
       mUndoingObject = false;
194
       }
195

    
196
     if( mCreatingCubits )
197
       {
198
       mPairs.clear();
199
       rescaleObject();
200

    
201
       if( mCubitsCreated )
202
         {
203
         mObject.createCubits(mQuatT,mQuatA,mScale);
204
         float[] dist = mObject.getDist3D();
205
         BandagedTouchControl control = mView.getTouchControl();
206
         control.setDist3D(dist);
207
         mScreen.detachAll();
208
         mView.resetCubits();
209
         mObject.attachCubits(mScaleValue);
210
         }
211

    
212
       mCreatingCubits = false;
213
       }
214

    
215
     if( mRescaling )
216
       {
217
       rescaleObject();
218
       mObject.scaleCubits(mScaleValue);
219
       BandagedTouchControl control = mView.getTouchControl();
220
       control.setObjectRatio(mObjectScreenRatio);
221
       mRescaling = false;
222
       }
223
     }
224

    
225
///////////////////////////////////////////////////////////////////////////////////////////////////
226

    
227
   @Override
228
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
229
      {
230
      if( width!=mWidth || height!=mHeight )
231
        {
232
        mWidth = width;
233
        mHeight= height;
234
        rescaleObject();
235
        mScreen.detachAll();
236
        int touched = mView.getTouched();
237
        mObject.attachAndMarkCubits(mScaleValue,touched);
238
        mView.setScreenSize(width,height);
239
        mScreen.resize(width,height);
240
        }
241
      }
242

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244

    
245
   @Override
246
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
247
      {
248
      DistortedLibrary.setMax(EffectType.VERTEX,0);
249
      MeshBase.setMaxEffComponents(ObjectControl.MAX_MOVING_PARTS);
250
      FragmentEffectBrightness.enable();
251
      DistortedLibrary.onSurfaceCreated(this,1);
252
      DistortedLibrary.setCull(true);
253
      mObject.recreateCubits(mQuatT,mQuatA,mScale);
254
      mCubitsCreated = true;
255
      mWidth = 0;
256
      mHeight= 0;
257
      }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260

    
261
   public DistortedScreen getScreen()
262
     {
263
     return mScreen;
264
     }
265

    
266
///////////////////////////////////////////////////////////////////////////////////////////////////
267

    
268
   void setConnecting(int index1, int index2)
269
     {
270
     mIndex1 = index1;
271
     mIndex2 = index2;
272
     mConnectingCubits = true;
273
     }
274

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

    
277
   public Static4D getQuatAccu()
278
     {
279
     return mQuatA;
280
     }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283

    
284
   public void setQuatTemp(float x, float y, float z, float w)
285
     {
286
     mSetQuatT = false;
287

    
288
     mQuatX = x;
289
     mQuatY = y;
290
     mQuatZ = z;
291
     mQuatW = w;
292

    
293
     mSetQuatT = true;
294
     }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
   public void resetQuats()
299
     {
300
     mResetQuats = true;
301
     }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

    
305
   public boolean isBusy()
306
     {
307
     return (mResettingObject || mCreatingCubits || mConnectingCubits);
308
     }
309

    
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311

    
312
   public void saveObject()
313
     {
314
     TwistyObject obj = mObject.createObject(TwistyObject.MODE_NORM, 1.0f );
315
     String name = obj.getShortName();
316
     BandagedActivity act = (BandagedActivity) mView.getContext();
317

    
318
     if( act.objectDoesntExist(name) && createObjectJson(obj,act) )
319
       {
320
       setupIconCreation(act);
321
       act.addObject(obj.getShortName());
322
       act.doNotShowDialogAnymore();
323
       }
324
     }
325

    
326
///////////////////////////////////////////////////////////////////////////////////////////////////
327

    
328
   private int packTwoIntsIntoPair(int index1, int index2)
329
     {
330
     return (index1<<16) + index2;
331
     }
332

    
333
///////////////////////////////////////////////////////////////////////////////////////////////////
334

    
335
   private int getFirstFromPair(int pair)
336
     {
337
     return pair>>16;
338
     }
339

    
340
///////////////////////////////////////////////////////////////////////////////////////////////////
341

    
342
   private int getSecondFromPair(int pair)
343
     {
344
     return pair&0xffff;
345
     }
346

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

    
349
   private boolean createObjectJson(TwistyObject object, Activity act)
350
     {
351
     final String name = object.getShortName()+"_object.json";
352
     File file = new File(act.getFilesDir(), name);
353
     String filename = file.getAbsolutePath();
354

    
355
     try
356
       {
357
       JsonWriter writer = JsonWriter.getInstance();
358
       String json = writer.createObjectString(object);
359
       writer.write(filename,json);
360
       return true;
361
       }
362
     catch(JSONException ex)
363
       {
364
       act.runOnUiThread(new Runnable()
365
         {
366
         public void run()
367
           {
368
           String message = "JSON Exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
369
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
370
           }
371
         });
372

    
373
       return false;
374
       }
375
     catch(FileNotFoundException ex)
376
       {
377
       act.runOnUiThread(new Runnable()
378
         {
379
         public void run()
380
           {
381
           String message = "FileNotFound exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
382
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
383
           }
384
         });
385

    
386
       return false;
387
       }
388
     catch(IOException ex)
389
       {
390
       act.runOnUiThread(new Runnable()
391
         {
392
         public void run()
393
           {
394
           String message = "IO exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
395
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
396
           }
397
         });
398

    
399
       return false;
400
       }
401
     }
402

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

    
405
   private void setupIconCreation(Activity act)
406
     {
407
     final float R=1.0f;
408
     final int FBO_WIDTH  = (int)(R*720);
409
     final int FBO_HEIGHT = (int)(R*1280);
410
     final float OBJECT_SIZE = R*0.60f;
411

    
412
     TwistyObject obj = mObject.createObject(TwistyObject.MODE_ICON, OBJECT_SIZE );
413
     DistortedEffects effects = obj.getObjectEffects();
414
     DistortedNode node = obj.getNode();
415

    
416
     if( mFramebuffer==null )
417
       {
418
       mFramebuffer = new DistortedFramebuffer(FBO_WIDTH,FBO_HEIGHT,1, InternalOutputSurface.DEPTH_NO_STENCIL);
419
       mFramebuffer.glClearColor(0,0,0,0);
420
       }
421

    
422
     mFramebuffer.setProjection( mObject.computeProjectionAngle() ,0.1f);
423
     mFramebuffer.detachAll();
424
     mFramebuffer.attach(node);
425

    
426
     Static1D halo = new Static1D(5);
427
     Static4D color = new Static4D(0,0,0,1);
428
     PostprocessEffectBorder border = new PostprocessEffectBorder(halo,color);
429
     border.setHaloDepth(false);
430
     effects.apply(border);
431

    
432
     final String name = obj.getShortName()+".png";
433
     File file = new File(act.getFilesDir(), name);
434
     String filename = file.getAbsolutePath();
435

    
436
     mSaveIcon = 0;
437
     mPath = filename;
438
     }
439

    
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441

    
442
   private void renderIcon(long time)
443
     {
444
     mFramebuffer.render(time);
445
     }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

    
449
   private void saveIcon()
450
     {
451
     int fW = mFramebuffer.getWidth();
452
     int fH = mFramebuffer.getHeight();
453

    
454
     ByteBuffer buf = ByteBuffer.allocateDirect(fW*fH*4);
455
     buf.order(ByteOrder.LITTLE_ENDIAN);
456

    
457
     mFramebuffer.setAsReadFramebuffer(0);
458
     GLES31.glReadBuffer(GLES31.GL_COLOR_ATTACHMENT0);
459
     GLES31.glReadPixels( 0, 0, fW, fH, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, buf);
460
     BandagedWorkerThread.newBuffer(buf,fW,fH,6,mPath);
461
     GLES31.glBindFramebuffer(GLES31.GL_READ_FRAMEBUFFER, 0);
462

    
463
     mSaveIcon = -1;
464
     }
465

    
466
///////////////////////////////////////////////////////////////////////////////////////////////////
467

    
468
   void mulObjectRatio(float ratio)
469
     {
470
     mObjectScreenRatio *= ratio;
471

    
472
     if( mObjectScreenRatio>MAX_SIZE_CHANGE*mInitRatio) mObjectScreenRatio = MAX_SIZE_CHANGE*mInitRatio;
473
     if( mObjectScreenRatio<MIN_SIZE_CHANGE*mInitRatio) mObjectScreenRatio = MIN_SIZE_CHANGE*mInitRatio;
474

    
475
     mRescaling = true;
476
     }
477

    
478
///////////////////////////////////////////////////////////////////////////////////////////////////
479

    
480
   float getObjectRatio()
481
     {
482
     return mObjectScreenRatio;
483
     }
484

    
485
///////////////////////////////////////////////////////////////////////////////////////////////////
486

    
487
   private void rescaleObject()
488
     {
489
     float size = mObject.getMaxSize();
490
     final float Q = mObjectScreenRatio/size;
491
     mScaleValue = mWidth<mHeight ? Q*mWidth : Q*mHeight;
492
     mScale.set( mScaleValue,mScaleValue,mScaleValue );
493
     }
494

    
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496

    
497
   public void changeObject(int x, int y, int z)
498
     {
499
     if( mObject.tryChangeObject(x,y,z) ) mCreatingCubits = true;
500
     }
501

    
502
///////////////////////////////////////////////////////////////////////////////////////////////////
503

    
504
   public void displaySavingDialog()
505
     {
506
     BandagedActivity act = (BandagedActivity)mView.getContext();
507
     DialogBandagedSave saveDiag = new DialogBandagedSave();
508
     saveDiag.show(act.getSupportFragmentManager(), null);
509
     }
510

    
511
///////////////////////////////////////////////////////////////////////////////////////////////////
512

    
513
   public void setupReset()
514
     {
515
     mResettingObject = true;
516
     mInitialPhase    = true;
517
     mStartTime       = System.currentTimeMillis();
518
     }
519

    
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521

    
522
   public void setupUndo()
523
     {
524
     mUndoingObject = true;
525
     }
526

    
527
///////////////////////////////////////////////////////////////////////////////////////////////////
528

    
529
   public boolean continueResetting(long time)
530
     {
531
     long diff = time-mStartTime;
532
     float quotient = ((float)diff)/RESET_DURATION;
533

    
534
     if( mInitialPhase && quotient>0.5f )
535
       {
536
       mInitialPhase=false;
537
       mView.resetCubits();
538
       mObject.resetObject(mScaleValue);
539
       }
540

    
541
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
542

    
543
     float sinA = (float)Math.sin(angle);
544
     float cosA = (float)Math.cos(angle);
545

    
546
     mQuatT.set(0, -sinA, 0, cosA);
547

    
548
     return quotient>1.0f;
549
     }
550

    
551
///////////////////////////////////////////////////////////////////////////////////////////////////
552

    
553
  public void touchCubit(int index)
554
    {
555
    mObject.touchCubit(index);
556
    }
557

    
558
///////////////////////////////////////////////////////////////////////////////////////////////////
559

    
560
  public void untouchCubit(int index)
561
    {
562
    mObject.untouchCubit(index);
563
    }
564

    
565
///////////////////////////////////////////////////////////////////////////////////////////////////
566

    
567
  public BandagedTouchControl createTouchControl()
568
    {
569
    return new BandagedTouchControl( getObjectRatio() , mScreen.getFOV(), mObject );
570
    }
571

    
572
///////////////////////////////////////////////////////////////////////////////////////////////////
573

    
574
  public void distortedException(Exception ex)
575
    {
576
    android.util.Log.e("BandagedCreator", "unexpected exception: "+ex.getMessage() );
577
    }
578

    
579
///////////////////////////////////////////////////////////////////////////////////////////////////
580

    
581
  public InputStream localFile(int fileID)
582
    {
583
    return mResources.openRawResource(fileID);
584
    }
585

    
586
///////////////////////////////////////////////////////////////////////////////////////////////////
587

    
588
  public void logMessage(String message)
589
    {
590
    android.util.Log.e("BandagedCreator", message );
591
    }
592
}
(3-3/7)