Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube 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
// Magic Cube 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 Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.bandaged;
21

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

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

    
30
import org.distorted.dialogs.RubikDialogBandagedSave;
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.effect.VertexEffectDeform;
35
import org.distorted.library.main.DistortedEffects;
36
import org.distorted.library.main.DistortedFramebuffer;
37
import org.distorted.library.main.DistortedLibrary;
38
import org.distorted.library.main.DistortedNode;
39
import org.distorted.library.main.DistortedScreen;
40

    
41
import org.distorted.library.main.InternalOutputSurface;
42
import org.distorted.library.mesh.MeshBase;
43
import org.distorted.library.type.Static1D;
44
import org.distorted.library.type.Static3D;
45
import org.distorted.library.type.Static4D;
46
import org.distorted.objectlib.json.JsonWriter;
47
import org.distorted.objectlib.main.ShapeHexahedron;
48
import org.distorted.objectlib.main.TwistyObject;
49
import org.distorted.objectlib.objects.TwistyBandagedGeneric;
50
import org.json.JSONException;
51

    
52
import java.io.File;
53
import java.io.FileNotFoundException;
54
import java.io.IOException;
55
import java.nio.ByteBuffer;
56
import java.nio.ByteOrder;
57

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59

    
60
public class BandagedCreatorRenderer implements GLSurfaceView.Renderer, DistortedLibrary.ExceptionListener
61
{
62
   public static final float BRIGHTNESS = 0.333f;
63
   private static final int DURATION = 1000;
64

    
65
   static final float SCREEN_RATIO = 0.5f;
66
   static final float OBJECT_SIZE  = 3.0f;
67

    
68
   private final float[][] POSITIONS = new float[][]
69
        {
70
          {-1,  1,  1},
71
          {-1,  1,  0},
72
          {-1,  1, -1},
73
          {-1,  0,  1},
74
          {-1,  0,  0},
75
          {-1,  0, -1},
76
          {-1, -1,  1},
77
          {-1, -1,  0},
78
          {-1, -1, -1},
79
          { 0, -1,  1},
80
          { 0, -1,  0},
81
          { 0,  1,  1},
82
          { 0,  1,  0},
83
          { 0,  1, -1},
84
          { 0,  0,  1},
85
          { 0,  0, -1},
86
          { 1,  1,  1},
87
          { 1,  1,  0},
88
          { 1,  1, -1},
89
          { 1,  0,  1},
90
          { 1,  0,  0},
91
          { 1, -1,  1},
92
          { 1,  0, -1},
93
          { 1, -1, -1},
94
          { 1, -1,  0},
95
          { 0, -1, -1},
96
        };
97

    
98
   private final BandagedCreatorView mView;
99
   private final DistortedScreen mScreen;
100
   private final Static3D mScale;
101
   private final Static4D mQuatT, mQuatA;
102

    
103
   private BandagedCubit[] mCubits;
104
   private boolean mInitialPhase;
105
   private long mStartTime;
106
   private float mScaleValue;
107
   private float mX, mY, mZ, mW;
108
   private boolean mResetQuats, mSetQuatT, mResettingObject;
109
   private int mSaveIcon;
110
   private DistortedFramebuffer mFramebuffer;
111
   private String mPath;
112

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114

    
115
   BandagedCreatorRenderer(BandagedCreatorView v)
116
     {
117
     mQuatT = new Static4D(0,0,0,1);
118
     mQuatA = new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
119

    
120
     mView = v;
121

    
122
     mResetQuats     = false;
123
     mSetQuatT       = false;
124
     mResettingObject= false;
125

    
126
     mSaveIcon = -1;
127

    
128
     mScreen = new DistortedScreen();
129
     mScreen.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
130
     mScale = new Static3D(1,1,1);
131
     }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
   private boolean isAdjacent(float[] pos1, float[] pos2)
136
     {
137
     int len1 = pos1.length/3;
138
     int len2 = pos2.length/3;
139

    
140
     for(int i=0; i<len1; i++)
141
       for(int j=0; j<len2; j++)
142
         {
143
         float d0 = pos1[3*i  ] - pos2[3*j  ];
144
         float d1 = pos1[3*i+1] - pos2[3*j+1];
145
         float d2 = pos1[3*i+2] - pos2[3*j+2];
146

    
147
         if( d0*d0 + d1*d1 + d2*d2 == 1 ) return true;
148
         }
149

    
150
     return false;
151
     }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

    
155
   private BandagedCubit[] createCubits()
156
     {
157
     boolean roundCorners = DistortedLibrary.fastCompilationTF();
158
     int len = POSITIONS.length;
159
     BandagedCubit[] cubits = new BandagedCubit[len];
160

    
161
     for(int c=0; c<len; c++)
162
       {
163
       cubits[c] = new BandagedCubit(POSITIONS[c],mQuatT,mQuatA,mScale,roundCorners);
164
       }
165

    
166
     return cubits;
167
     }
168

    
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170

    
171
   private void resetObject()
172
     {
173
     mView.resetCubits();
174

    
175
     int len = POSITIONS.length;
176

    
177
     for(int c=0; c<len; c++)
178
       {
179
       if( !mCubits[c].isAttached() )
180
         {
181
         mCubits[c].attach();
182
         mCubits[c].setUnmarked();
183
         mScreen.attach(mCubits[c].getNode());
184
         }
185
       if( mCubits[c].getPosition().length>3 )
186
         {
187
         mCubits[c].reset(mScaleValue);
188
         }
189
       }
190
     }
191

    
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193

    
194
   @Override
195
   public void onDrawFrame(GL10 glUnused)
196
     {
197
     long time = System.currentTimeMillis();
198
     mScreen.render(time);
199

    
200
     if( mSetQuatT )
201
       {
202
       mSetQuatT = false;
203
       mQuatT.set(mX,mY,mZ,mW);
204
       }
205

    
206
     if( mResetQuats )
207
       {
208
       mResetQuats = false;
209

    
210
       float qx = mQuatT.get0();
211
       float qy = mQuatT.get1();
212
       float qz = mQuatT.get2();
213
       float qw = mQuatT.get3();
214

    
215
       float rx = mQuatA.get0();
216
       float ry = mQuatA.get1();
217
       float rz = mQuatA.get2();
218
       float rw = mQuatA.get3();
219

    
220
       float tx = rw*qx - rz*qy + ry*qz + rx*qw;
221
       float ty = rw*qy + rz*qx + ry*qw - rx*qz;
222
       float tz = rw*qz + rz*qw - ry*qx + rx*qy;
223
       float tw = rw*qw - rz*qz - ry*qy - rx*qx;
224

    
225
       mQuatT.set(0f, 0f, 0f, 1f);
226
       mQuatA.set(tx, ty, tz, tw);
227
       }
228

    
229
     if( mResettingObject )
230
       {
231
       boolean done = continueResetting(time);
232
       if( done ) mResettingObject = false;
233
       }
234

    
235
     if( mSaveIcon>=0 )
236
       {
237
       renderIcon(time); // for some reason we need to call render() twice here, otherwise the
238
       mSaveIcon++;      // icon turns out black. Probably some problem with binding the texture.
239
       }
240
     if( mSaveIcon>=2 )
241
       {
242
       saveIcon();
243
       mSaveIcon = -1;
244
       }
245
     }
246

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

    
249
   @Override
250
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
251
      {
252
      final float Q = SCREEN_RATIO/OBJECT_SIZE;
253
      mScaleValue = width<height ? Q*width : Q*height;
254

    
255
      mScreen.detachAll();
256
      int len = POSITIONS.length;
257
      int touched = mView.getTouched();
258

    
259
      for(int i=0; i<len; i++)
260
        if( mCubits[i].isAttached() )
261
          {
262
          mCubits[i].scaleMove(mScaleValue);
263
          if( touched==i ) mCubits[i].setMarked();
264
          else             mCubits[i].setUnmarked();
265
          DistortedNode node = mCubits[i].getNode();
266
          mScreen.attach(node);
267
          }
268

    
269
      mScale.set( mScaleValue,mScaleValue,mScaleValue );
270
      mView.setScreenSize(width,height);
271
      mScreen.resize(width,height);
272
      }
273

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

    
276
   @Override
277
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
278
      {
279
      DistortedLibrary.setMax(EffectType.VERTEX,25);
280
      MeshBase.setMaxEffComponents(50);
281

    
282
      VertexEffectDeform.enable();
283
      FragmentEffectBrightness.enable();
284

    
285
      DistortedLibrary.onSurfaceCreated(mView.getContext(),this,1);
286
      DistortedLibrary.setCull(true);
287

    
288
      mCubits= createCubits();
289
      mView.setCubits(mCubits);
290
      }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
   public void distortedException(Exception ex)
295
     {
296
     android.util.Log.e("CREATOR", "unexpected exception: "+ex.getMessage() );
297
     }
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300

    
301
   public BandagedCubit[] getCubits()
302
     {
303
     return mCubits;
304
     }
305

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307

    
308
   public DistortedScreen getScreen()
309
     {
310
     return mScreen;
311
     }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314

    
315
   public void tryConnectingCubits(int index1, int index2)
316
     {
317
     if( index1!=index2 )
318
       {
319
       float[] pos1 = mCubits[index1].getPosition();
320
       float[] pos2 = mCubits[index2].getPosition();
321

    
322
       if( isAdjacent(pos1,pos2) )
323
         {
324
         mCubits[index2].join(pos1,mScaleValue);
325
         mCubits[index1].detach();
326
         mScreen.detach(mCubits[index1].getNode());
327
         }
328
       }
329
     }
330

    
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332

    
333
   public Static4D getQuatAccu()
334
     {
335
     return mQuatA;
336
     }
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339

    
340
   public void setQuatTemp(float x, float y, float z, float w)
341
     {
342
     mX = x;
343
     mY = y;
344
     mZ = z;
345
     mW = w;
346

    
347
     mSetQuatT = true;
348
     }
349

    
350
///////////////////////////////////////////////////////////////////////////////////////////////////
351

    
352
   public void resetQuats()
353
     {
354
     mResetQuats = true;
355
     }
356

    
357
///////////////////////////////////////////////////////////////////////////////////////////////////
358

    
359
   public boolean isBusy()
360
     {
361
     return mResettingObject;
362
     }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
   public void saveObject()
367
     {
368
     int len = POSITIONS.length;
369
     int numAttached=0;
370

    
371
     for(int i=0; i<len; i++)
372
       if( mCubits[i].isAttached() ) numAttached++;
373

    
374
     float[][] pos = new float[numAttached][];
375
     int attached=0;
376

    
377
     for(int i=0; i<len; i++)
378
       if( mCubits[i].isAttached() )
379
         {
380
         pos[attached++] = mCubits[i].getPosition();
381
         }
382

    
383
     TwistyBandagedGeneric.setPositions(pos);
384
     TwistyObject obj = new TwistyBandagedGeneric( new Static4D(0,0,0,1), 1.0f, TwistyObject.MODE_NORM);
385
     String name = obj.getShortName();
386
     BandagedCreatorActivity act = (BandagedCreatorActivity) mView.getContext();
387

    
388
     if( act.objectDoesntExist(name) && createObjectJson(obj,act) )
389
       {
390
       setupIconCreation(act);
391
       act.addObject(obj.getShortName());
392
       }
393
     }
394

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

    
397
   private boolean createObjectJson(TwistyObject object, Activity act)
398
     {
399
     final String name = object.getShortName()+"_object.json";
400
     File file = new File(act.getFilesDir(), name);
401
     String filename = file.getAbsolutePath();
402

    
403
     try
404
       {
405
       JsonWriter writer = JsonWriter.getInstance();
406
       String json = writer.createObjectString(object,24);
407
       writer.write(filename,json);
408
       return true;
409
       }
410
     catch(JSONException ex)
411
       {
412
       act.runOnUiThread(new Runnable()
413
         {
414
         public void run()
415
           {
416
           String message = "JSON Exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
417
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
418
           }
419
         });
420

    
421
       return false;
422
       }
423
     catch(FileNotFoundException ex)
424
       {
425
       act.runOnUiThread(new Runnable()
426
         {
427
         public void run()
428
           {
429
           String message = "FileNotFound exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
430
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
431
           }
432
         });
433

    
434
       return false;
435
       }
436
     catch(IOException ex)
437
       {
438
       act.runOnUiThread(new Runnable()
439
         {
440
         public void run()
441
           {
442
           String message = "IO exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
443
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
444
           }
445
         });
446

    
447
       return false;
448
       }
449
     }
450

    
451
///////////////////////////////////////////////////////////////////////////////////////////////////
452

    
453
   private void setupIconCreation(Activity act)
454
     {
455
     final float R=1.0f;
456
     final int FBO_WIDTH  = (int)(R*240);
457
     final int FBO_HEIGHT = (int)(R*360);
458
     final float OBJECT_SIZE = R*0.38f;
459

    
460
     TwistyObject object = new TwistyBandagedGeneric(ShapeHexahedron.DEFAULT_ROT, OBJECT_SIZE, TwistyObject.MODE_ICON);
461
     DistortedEffects effects = object.getObjectEffects();
462
     DistortedNode node = object.getNode();
463

    
464
     if( mFramebuffer==null )
465
       {
466
       mFramebuffer = new DistortedFramebuffer(FBO_WIDTH,FBO_HEIGHT,1, InternalOutputSurface.DEPTH_NO_STENCIL);
467
       mFramebuffer.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
468
       }
469

    
470
     mFramebuffer.detachAll();
471
     mFramebuffer.attach(node);
472

    
473
     Static1D halo = new Static1D(5);
474
     Static4D color = new Static4D(0,0,0,1);
475
     PostprocessEffectBorder border = new PostprocessEffectBorder(halo,color);
476
     border.setHaloDepth(false);
477
     effects.apply(border);
478

    
479
     final String name = object.getShortName()+".png";
480
     File file = new File(act.getFilesDir(), name);
481
     String filename = file.getAbsolutePath();
482

    
483
     mSaveIcon = 0;
484
     mPath = filename;
485
     }
486

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

    
489
   private void renderIcon(long time)
490
     {
491
     mFramebuffer.render(time);
492
     }
493

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

    
496
   private void saveIcon()
497
     {
498
     int fW = mFramebuffer.getWidth();
499
     int fH = mFramebuffer.getHeight();
500

    
501
     ByteBuffer buf = ByteBuffer.allocateDirect(fW*fH*4);
502
     buf.order(ByteOrder.LITTLE_ENDIAN);
503

    
504
     mFramebuffer.setAsReadFramebuffer(0);
505
     GLES31.glReadBuffer(GLES31.GL_COLOR_ATTACHMENT0);
506
     GLES31.glReadPixels( 0, 0, fW, fH, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, buf);
507
     BandagedCreatorWorkerThread.newBuffer(buf,fW,fH,6,mPath);
508
     GLES31.glBindFramebuffer(GLES31.GL_READ_FRAMEBUFFER, 0);
509

    
510
     mSaveIcon = -1;
511
     }
512

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

    
515
   public void displaySavingDialog()
516
     {
517
     BandagedCreatorActivity act = (BandagedCreatorActivity)mView.getContext();
518
     RubikDialogBandagedSave saveDiag = new RubikDialogBandagedSave();
519
     saveDiag.show(act.getSupportFragmentManager(), null);
520
     }
521

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

    
524
   public void setupReset()
525
     {
526
     mResettingObject = true;
527
     mInitialPhase    = true;
528
     mStartTime       = System.currentTimeMillis();
529
     }
530

    
531
///////////////////////////////////////////////////////////////////////////////////////////////////
532

    
533
   public boolean continueResetting(long time)
534
     {
535
     long diff = time-mStartTime;
536
     float quotient = ((float)diff)/DURATION;
537

    
538
     if( mInitialPhase && quotient>0.5f )
539
       {
540
       mInitialPhase=false;
541
       resetObject();
542
       }
543

    
544
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
545

    
546
     float sinA = (float)Math.sin(angle);
547
     float cosA = (float)Math.cos(angle);
548

    
549
     mQuatT.set(0, -sinA, 0, cosA);
550

    
551
     return quotient>1.0f;
552
     }
553

    
554
///////////////////////////////////////////////////////////////////////////////////////////////////
555

    
556
  public void touchCubit(int index)
557
    {
558
    mCubits[index].setMarked();
559
    }
560

    
561
///////////////////////////////////////////////////////////////////////////////////////////////////
562

    
563
  public void untouchCubit(int index)
564
    {
565
    mCubits[index].setUnmarked();
566
    }
567
}
(3-3/13)