Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorRenderer.java @ f404152d

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.json.JsonWriter;
43
import org.distorted.objectlib.main.TwistyObject;
44

    
45
import org.json.JSONException;
46

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
public class BandagedCreatorRenderer implements GLSurfaceView.Renderer, DistortedLibrary.LibraryUser
50
{
51
   public static final float BRIGHTNESS = 0.333f;
52
   private static final int RESET_DURATION = 1000;
53
   private static final float MAX_SIZE_CHANGE = 1.70f;
54
   private static final float MIN_SIZE_CHANGE = 0.50f;
55
   private static final float INIT_RATIO = 0.5f;
56

    
57
   private final BandagedCreatorView mView;
58
   private final Resources mResources;
59
   private final DistortedScreen mScreen;
60
   private final Static3D mScale;
61
   private final Static4D mQuatT, mQuatA;
62
   private final BandagedObject mObject;
63

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

    
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77

    
78
   BandagedCreatorRenderer(BandagedCreatorView v)
79
     {
80
     mView = v;
81
     mResources = v.getResources();
82

    
83
     mQuatT = new Static4D(0,0,0,1);
84
     mQuatA = new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
85

    
86
     mResetQuats       = false;
87
     mSetQuatT         = false;
88
     mResettingObject  = false;
89
     mConnectingCubits = false;
90
     mCubitsCreated    = false;
91
     mCreatingCubits   = false;
92
     mRescaling        = false;
93

    
94
     mObjectScreenRatio= INIT_RATIO;
95
     mSaveIcon = -1;
96

    
97
     mScreen = new DistortedScreen();
98
     mScreen.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
99
     mScale = new Static3D(1,1,1);
100
     mObject = new BandagedObject(mScreen);
101
     }
102

    
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104

    
105
   @Override
106
   public void onDrawFrame(GL10 glUnused)
107
     {
108
     long time = System.currentTimeMillis();
109
     mScreen.render(time);
110

    
111
     if( mSetQuatT )
112
       {
113
       mSetQuatT = false;
114
       mQuatT.set(mQuatX,mQuatY,mQuatZ,mQuatW);
115
       }
116

    
117
     if( mResetQuats )
118
       {
119
       mResetQuats = false;
120

    
121
       float qx = mQuatT.get0();
122
       float qy = mQuatT.get1();
123
       float qz = mQuatT.get2();
124
       float qw = mQuatT.get3();
125

    
126
       float rx = mQuatA.get0();
127
       float ry = mQuatA.get1();
128
       float rz = mQuatA.get2();
129
       float rw = mQuatA.get3();
130

    
131
       float tx = rw*qx - rz*qy + ry*qz + rx*qw;
132
       float ty = rw*qy + rz*qx + ry*qw - rx*qz;
133
       float tz = rw*qz + rz*qw - ry*qx + rx*qy;
134
       float tw = rw*qw - rz*qz - ry*qy - rx*qx;
135

    
136
       mQuatT.set(0f, 0f, 0f, 1f);
137
       mQuatA.set(tx, ty, tz, tw);
138
       }
139

    
140
     if( mResettingObject )
141
       {
142
       boolean done = continueResetting(time);
143
       if( done ) mResettingObject = false;
144
       }
145

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

    
157
     if( mConnectingCubits )
158
       {
159
       mConnectingCubits = false;
160
       mObject.tryConnectingCubits(mIndex1,mIndex2,mScaleValue);
161
       }
162

    
163
     if( mCreatingCubits )
164
       {
165
       mCreatingCubits = false;
166
       rescaleObject();
167

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

    
180
     if( mRescaling )
181
       {
182
       mRescaling = false;
183
       rescaleObject();
184
       mObject.scaleCubits(mScaleValue);
185
       BandagedCreatorTouchControl control = mView.getTouchControl();
186
       control.setObjectRatio(mObjectScreenRatio);
187
       }
188
     }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191

    
192
   @Override
193
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
194
      {
195
      if( width!=mWidth || height!=mHeight )
196
        {
197
        mWidth = width;
198
        mHeight= height;
199
        rescaleObject();
200
        mScreen.detachAll();
201
        int touched = mView.getTouched();
202
        mObject.attachAndMarkCubits(mScaleValue,touched);
203
        mView.setScreenSize(width,height);
204
        mScreen.resize(width,height);
205
        }
206
      }
207

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209

    
210
   @Override
211
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
212
      {
213
      DistortedLibrary.setMax(EffectType.VERTEX,0);
214
      MeshBase.setMaxEffComponents(120); // what?
215
      FragmentEffectBrightness.enable();
216
      DistortedLibrary.onSurfaceCreated(this,1);
217
      DistortedLibrary.setCull(true);
218
      mObject.recreateCubits(mQuatT,mQuatA,mScale);
219
      mCubitsCreated = true;
220
      mWidth = 0;
221
      mHeight= 0;
222
      }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

    
226
   public DistortedScreen getScreen()
227
     {
228
     return mScreen;
229
     }
230

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

    
233
   void setConnecting(int index1, int index2)
234
     {
235
     mIndex1 = index1;
236
     mIndex2 = index2;
237
     mConnectingCubits = true;
238
     }
239

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

    
242
   public Static4D getQuatAccu()
243
     {
244
     return mQuatA;
245
     }
246

    
247
///////////////////////////////////////////////////////////////////////////////////////////////////
248

    
249
   public void setQuatTemp(float x, float y, float z, float w)
250
     {
251
     mSetQuatT = false;
252

    
253
     mQuatX = x;
254
     mQuatY = y;
255
     mQuatZ = z;
256
     mQuatW = w;
257

    
258
     mSetQuatT = true;
259
     }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
   public void resetQuats()
264
     {
265
     mResetQuats = true;
266
     }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
   public boolean isBusy()
271
     {
272
     return mResettingObject;
273
     }
274

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

    
277
   public void saveObject()
278
     {
279
     TwistyObject obj = mObject.createObject(TwistyObject.MODE_NORM, 1.0f );
280
     String name = obj.getShortName();
281
     BandagedCreatorActivity act = (BandagedCreatorActivity) mView.getContext();
282

    
283
     if( act.objectDoesntExist(name) && createObjectJson(obj,act) )
284
       {
285
       setupIconCreation(act);
286
       act.addObject(obj.getShortName());
287
       }
288
     }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
   private boolean createObjectJson(TwistyObject object, Activity act)
293
     {
294
     final String name = object.getShortName()+"_object.json";
295
     File file = new File(act.getFilesDir(), name);
296
     String filename = file.getAbsolutePath();
297

    
298
     try
299
       {
300
       JsonWriter writer = JsonWriter.getInstance();
301
       String json = writer.createObjectString(object,24,0);
302
       writer.write(filename,json);
303
       return true;
304
       }
305
     catch(JSONException ex)
306
       {
307
       act.runOnUiThread(new Runnable()
308
         {
309
         public void run()
310
           {
311
           String message = "JSON Exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
312
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
313
           }
314
         });
315

    
316
       return false;
317
       }
318
     catch(FileNotFoundException ex)
319
       {
320
       act.runOnUiThread(new Runnable()
321
         {
322
         public void run()
323
           {
324
           String message = "FileNotFound exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
325
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
326
           }
327
         });
328

    
329
       return false;
330
       }
331
     catch(IOException ex)
332
       {
333
       act.runOnUiThread(new Runnable()
334
         {
335
         public void run()
336
           {
337
           String message = "IO exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
338
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
339
           }
340
         });
341

    
342
       return false;
343
       }
344
     }
345

    
346
///////////////////////////////////////////////////////////////////////////////////////////////////
347

    
348
   private void setupIconCreation(Activity act)
349
     {
350
     final float R=1.0f;
351
     final int FBO_WIDTH  = (int)(R*720);
352
     final int FBO_HEIGHT = (int)(R*1280);
353
     final float OBJECT_SIZE = R*0.35f;
354

    
355
     TwistyObject obj = mObject.createObject(TwistyObject.MODE_ICON, OBJECT_SIZE );
356
     DistortedEffects effects = obj.getObjectEffects();
357
     DistortedNode node = obj.getNode();
358

    
359
     if( mFramebuffer==null )
360
       {
361
       mFramebuffer = new DistortedFramebuffer(FBO_WIDTH,FBO_HEIGHT,1, InternalOutputSurface.DEPTH_NO_STENCIL);
362
       mFramebuffer.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
363
       }
364

    
365
     mFramebuffer.setProjection( mObject.computeProjectionAngle() ,0.1f);
366
     mFramebuffer.detachAll();
367
     mFramebuffer.attach(node);
368

    
369
     Static1D halo = new Static1D(5);
370
     Static4D color = new Static4D(0,0,0,1);
371
     PostprocessEffectBorder border = new PostprocessEffectBorder(halo,color);
372
     border.setHaloDepth(false);
373
     effects.apply(border);
374

    
375
     final String name = obj.getShortName()+".png";
376
     File file = new File(act.getFilesDir(), name);
377
     String filename = file.getAbsolutePath();
378

    
379
     mSaveIcon = 0;
380
     mPath = filename;
381
     }
382

    
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384

    
385
   private void renderIcon(long time)
386
     {
387
     mFramebuffer.render(time);
388
     }
389

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

    
392
   private void saveIcon()
393
     {
394
     int fW = mFramebuffer.getWidth();
395
     int fH = mFramebuffer.getHeight();
396

    
397
     ByteBuffer buf = ByteBuffer.allocateDirect(fW*fH*4);
398
     buf.order(ByteOrder.LITTLE_ENDIAN);
399

    
400
     mFramebuffer.setAsReadFramebuffer(0);
401
     GLES31.glReadBuffer(GLES31.GL_COLOR_ATTACHMENT0);
402
     GLES31.glReadPixels( 0, 0, fW, fH, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, buf);
403
     BandagedCreatorWorkerThread.newBuffer(buf,fW,fH,6,mPath);
404
     GLES31.glBindFramebuffer(GLES31.GL_READ_FRAMEBUFFER, 0);
405

    
406
     mSaveIcon = -1;
407
     }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
   void mulObjectRatio(float ratio)
412
     {
413
     mObjectScreenRatio *= ratio;
414

    
415
     if( mObjectScreenRatio>MAX_SIZE_CHANGE*INIT_RATIO) mObjectScreenRatio = MAX_SIZE_CHANGE*INIT_RATIO;
416
     if( mObjectScreenRatio<MIN_SIZE_CHANGE*INIT_RATIO) mObjectScreenRatio = MIN_SIZE_CHANGE*INIT_RATIO;
417

    
418
     mRescaling = true;
419
     }
420

    
421
///////////////////////////////////////////////////////////////////////////////////////////////////
422

    
423
   float getObjectRatio()
424
     {
425
     return mObjectScreenRatio;
426
     }
427

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

    
430
   private void rescaleObject()
431
     {
432
     float size = mObject.getSize();
433
     final float Q = mObjectScreenRatio/size;
434
     mScaleValue = mWidth<mHeight ? Q*mWidth : Q*mHeight;
435
     mScale.set( mScaleValue,mScaleValue,mScaleValue );
436
     }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
   public void changeObject(int x, int y, int z)
441
     {
442
     if( mObject.tryChangeObject(x,y,z) ) mCreatingCubits = true;
443
     }
444

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

    
447
   public void displaySavingDialog()
448
     {
449
     BandagedCreatorActivity act = (BandagedCreatorActivity)mView.getContext();
450
     RubikDialogBandagedSave saveDiag = new RubikDialogBandagedSave();
451
     saveDiag.show(act.getSupportFragmentManager(), null);
452
     }
453

    
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455

    
456
   public void setupReset()
457
     {
458
     mResettingObject = true;
459
     mInitialPhase    = true;
460
     mStartTime       = System.currentTimeMillis();
461
     }
462

    
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464

    
465
   public boolean continueResetting(long time)
466
     {
467
     long diff = time-mStartTime;
468
     float quotient = ((float)diff)/RESET_DURATION;
469

    
470
     if( mInitialPhase && quotient>0.5f )
471
       {
472
       mInitialPhase=false;
473
       mView.resetCubits();
474
       mObject.resetObject(mScaleValue);
475
       }
476

    
477
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
478

    
479
     float sinA = (float)Math.sin(angle);
480
     float cosA = (float)Math.cos(angle);
481

    
482
     mQuatT.set(0, -sinA, 0, cosA);
483

    
484
     return quotient>1.0f;
485
     }
486

    
487
///////////////////////////////////////////////////////////////////////////////////////////////////
488

    
489
  public void touchCubit(int index)
490
    {
491
    mObject.touchCubit(index);
492
    }
493

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

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

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

    
503
  public BandagedCreatorTouchControl createTouchControl()
504
    {
505
    return new BandagedCreatorTouchControl( getObjectRatio() , mScreen.getFOV(), mObject );
506
    }
507

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

    
510
  public void distortedException(Exception ex)
511
    {
512
    android.util.Log.e("BandagedCreator", "unexpected exception: "+ex.getMessage() );
513
    }
514

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

    
517
  public InputStream localFile(int fileID)
518
    {
519
    return mResources.openRawResource(fileID);
520
    }
521

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

    
524
  public void logMessage(String message)
525
    {
526
    android.util.Log.e("BandagedCreator", message );
527
    }
528
}
(3-3/14)