Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorRenderer.java @ 5a4ee169

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.TwistyObject;
46

    
47
import org.json.JSONException;
48

    
49
///////////////////////////////////////////////////////////////////////////////////////////////////
50

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

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

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

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

    
80
   BandagedCreatorRenderer(BandagedCreatorView v, int ordinal)
81
     {
82
     mView = v;
83
     mResources = v.getResources();
84

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

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

    
96
     mSaveIcon = -1;
97

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

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

    
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

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

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

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

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

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

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

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

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

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

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

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

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

    
182
       mCreatingCubits = false;
183
       }
184

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

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196

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

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

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

    
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230

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

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

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

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

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

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

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

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

    
263
     mSetQuatT = true;
264
     }
265

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

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

    
273
///////////////////////////////////////////////////////////////////////////////////////////////////
274

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

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

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

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

    
295
///////////////////////////////////////////////////////////////////////////////////////////////////
296

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

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

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

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

    
347
       return false;
348
       }
349
     }
350

    
351
///////////////////////////////////////////////////////////////////////////////////////////////////
352

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

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

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

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

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

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

    
384
     mSaveIcon = 0;
385
     mPath = filename;
386
     }
387

    
388
///////////////////////////////////////////////////////////////////////////////////////////////////
389

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

    
395
///////////////////////////////////////////////////////////////////////////////////////////////////
396

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

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

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

    
411
     mSaveIcon = -1;
412
     }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

    
416
   void mulObjectRatio(float ratio)
417
     {
418
     mObjectScreenRatio *= ratio;
419

    
420
     if( mObjectScreenRatio>MAX_SIZE_CHANGE*mInitRatio) mObjectScreenRatio = MAX_SIZE_CHANGE*mInitRatio;
421
     if( mObjectScreenRatio<MIN_SIZE_CHANGE*mInitRatio) mObjectScreenRatio = MIN_SIZE_CHANGE*mInitRatio;
422

    
423
     mRescaling = true;
424
     }
425

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

    
428
   float getObjectRatio()
429
     {
430
     return mObjectScreenRatio;
431
     }
432

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

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

    
443
///////////////////////////////////////////////////////////////////////////////////////////////////
444

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

    
450
///////////////////////////////////////////////////////////////////////////////////////////////////
451

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

    
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

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

    
468
///////////////////////////////////////////////////////////////////////////////////////////////////
469

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

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

    
482
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
483

    
484
     float sinA = (float)Math.sin(angle);
485
     float cosA = (float)Math.cos(angle);
486

    
487
     mQuatT.set(0, -sinA, 0, cosA);
488

    
489
     return quotient>1.0f;
490
     }
491

    
492
///////////////////////////////////////////////////////////////////////////////////////////////////
493

    
494
  public void touchCubit(int index)
495
    {
496
    mObject.touchCubit(index);
497
    }
498

    
499
///////////////////////////////////////////////////////////////////////////////////////////////////
500

    
501
  public void untouchCubit(int index)
502
    {
503
    mObject.untouchCubit(index);
504
    }
505

    
506
///////////////////////////////////////////////////////////////////////////////////////////////////
507

    
508
  public BandagedCreatorTouchControl createTouchControl()
509
    {
510
    return new BandagedCreatorTouchControl( getObjectRatio() , mScreen.getFOV(), mObject );
511
    }
512

    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514

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

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

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

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

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