Project

General

Profile

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

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

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, mConnectingCubits;
109
   private int mIndex1, mIndex2;
110
   private int mSaveIcon;
111
   private DistortedFramebuffer mFramebuffer;
112
   private String mPath;
113

    
114
///////////////////////////////////////////////////////////////////////////////////////////////////
115

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

    
121
     mView = v;
122

    
123
     mResetQuats       = false;
124
     mSetQuatT         = false;
125
     mResettingObject  = false;
126
     mConnectingCubits = false;
127

    
128
     mSaveIcon = -1;
129

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

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

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

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

    
149
         if( d0*d0 + d1*d1 + d2*d2 == 1 ) return true;
150
         }
151

    
152
     return false;
153
     }
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

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

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

    
168
     return cubits;
169
     }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172

    
173
   private void resetObject()
174
     {
175
     mView.resetCubits();
176

    
177
     int len = POSITIONS.length;
178

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

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195

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

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

    
208
     if( mResetQuats )
209
       {
210
       mResetQuats = false;
211

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

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

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

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

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

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

    
248
     if( mConnectingCubits )
249
       {
250
       mConnectingCubits = false;
251
       tryConnectingCubits(mIndex1,mIndex2);
252
       }
253
     }
254

    
255
///////////////////////////////////////////////////////////////////////////////////////////////////
256

    
257
   @Override
258
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
259
      {
260
      final float Q = SCREEN_RATIO/OBJECT_SIZE;
261
      mScaleValue = width<height ? Q*width : Q*height;
262

    
263
      mScreen.detachAll();
264
      int len = POSITIONS.length;
265
      int touched = mView.getTouched();
266

    
267
      for(int i=0; i<len; i++)
268
        if( mCubits[i].isAttached() )
269
          {
270
          mCubits[i].scaleMove(mScaleValue);
271
          if( touched==i ) mCubits[i].setMarked();
272
          else             mCubits[i].setUnmarked();
273
          DistortedNode node = mCubits[i].getNode();
274
          mScreen.attach(node);
275
          }
276

    
277
      mScale.set( mScaleValue,mScaleValue,mScaleValue );
278
      mView.setScreenSize(width,height);
279
      mScreen.resize(width,height);
280
      }
281

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

    
284
   @Override
285
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
286
      {
287
      DistortedLibrary.setMax(EffectType.VERTEX,25);
288
      MeshBase.setMaxEffComponents(50);
289

    
290
      VertexEffectDeform.enable();
291
      FragmentEffectBrightness.enable();
292

    
293
      DistortedLibrary.onSurfaceCreated(mView.getContext(),this,1);
294
      DistortedLibrary.setCull(true);
295

    
296
      mCubits= createCubits();
297
      mView.setCubits(mCubits);
298
      }
299

    
300
///////////////////////////////////////////////////////////////////////////////////////////////////
301

    
302
   public void distortedException(Exception ex)
303
     {
304
     android.util.Log.e("CREATOR", "unexpected exception: "+ex.getMessage() );
305
     }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

    
309
   public BandagedCubit[] getCubits()
310
     {
311
     return mCubits;
312
     }
313

    
314
///////////////////////////////////////////////////////////////////////////////////////////////////
315

    
316
   public DistortedScreen getScreen()
317
     {
318
     return mScreen;
319
     }
320

    
321
///////////////////////////////////////////////////////////////////////////////////////////////////
322

    
323
   void setConnecting(int index1, int index2)
324
     {
325
     mIndex1 = index1;
326
     mIndex2 = index2;
327
     mConnectingCubits = true;
328
     }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
   private void tryConnectingCubits(int index1, int index2)
333
     {
334
     if( index1!=index2 )
335
       {
336
       float[] pos1 = mCubits[index1].getPosition();
337
       float[] pos2 = mCubits[index2].getPosition();
338

    
339
       if( isAdjacent(pos1,pos2) )
340
         {
341
         mCubits[index2].join(pos1,mScaleValue);
342
         mCubits[index1].detach();
343
         mScreen.detach(mCubits[index1].getNode());
344
         }
345
       }
346
     }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
   public Static4D getQuatAccu()
351
     {
352
     return mQuatA;
353
     }
354

    
355
///////////////////////////////////////////////////////////////////////////////////////////////////
356

    
357
   public void setQuatTemp(float x, float y, float z, float w)
358
     {
359
     mX = x;
360
     mY = y;
361
     mZ = z;
362
     mW = w;
363

    
364
     mSetQuatT = true;
365
     }
366

    
367
///////////////////////////////////////////////////////////////////////////////////////////////////
368

    
369
   public void resetQuats()
370
     {
371
     mResetQuats = true;
372
     }
373

    
374
///////////////////////////////////////////////////////////////////////////////////////////////////
375

    
376
   public boolean isBusy()
377
     {
378
     return mResettingObject;
379
     }
380

    
381
///////////////////////////////////////////////////////////////////////////////////////////////////
382

    
383
   public void saveObject()
384
     {
385
     int len = POSITIONS.length;
386
     int numAttached=0;
387

    
388
     for(int i=0; i<len; i++)
389
       if( mCubits[i].isAttached() ) numAttached++;
390

    
391
     float[][] pos = new float[numAttached][];
392
     int attached=0;
393

    
394
     for(int i=0; i<len; i++)
395
       if( mCubits[i].isAttached() )
396
         {
397
         pos[attached++] = mCubits[i].getPosition();
398
         }
399

    
400
     TwistyBandagedGeneric.setPositions(pos);
401
     TwistyObject obj = new TwistyBandagedGeneric( new Static4D(0,0,0,1), 1.0f, TwistyObject.MODE_NORM);
402
     String name = obj.getShortName();
403
     BandagedCreatorActivity act = (BandagedCreatorActivity) mView.getContext();
404

    
405
     if( act.objectDoesntExist(name) && createObjectJson(obj,act) )
406
       {
407
       setupIconCreation(act);
408
       act.addObject(obj.getShortName());
409
       }
410
     }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413

    
414
   private boolean createObjectJson(TwistyObject object, Activity act)
415
     {
416
     final String name = object.getShortName()+"_object.json";
417
     File file = new File(act.getFilesDir(), name);
418
     String filename = file.getAbsolutePath();
419

    
420
     try
421
       {
422
       JsonWriter writer = JsonWriter.getInstance();
423
       String json = writer.createObjectString(object,24);
424
       writer.write(filename,json);
425
       return true;
426
       }
427
     catch(JSONException ex)
428
       {
429
       act.runOnUiThread(new Runnable()
430
         {
431
         public void run()
432
           {
433
           String message = "JSON Exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
434
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
435
           }
436
         });
437

    
438
       return false;
439
       }
440
     catch(FileNotFoundException ex)
441
       {
442
       act.runOnUiThread(new Runnable()
443
         {
444
         public void run()
445
           {
446
           String message = "FileNotFound exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
447
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
448
           }
449
         });
450

    
451
       return false;
452
       }
453
     catch(IOException ex)
454
       {
455
       act.runOnUiThread(new Runnable()
456
         {
457
         public void run()
458
           {
459
           String message = "IO exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
460
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
461
           }
462
         });
463

    
464
       return false;
465
       }
466
     }
467

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

    
470
   private void setupIconCreation(Activity act)
471
     {
472
     final float R=1.0f;
473
     final int FBO_WIDTH  = (int)(R*240);
474
     final int FBO_HEIGHT = (int)(R*360);
475
     final float OBJECT_SIZE = R*0.38f;
476

    
477
     TwistyObject object = new TwistyBandagedGeneric(ShapeHexahedron.DEFAULT_ROT, OBJECT_SIZE, TwistyObject.MODE_ICON);
478
     DistortedEffects effects = object.getObjectEffects();
479
     DistortedNode node = object.getNode();
480

    
481
     if( mFramebuffer==null )
482
       {
483
       mFramebuffer = new DistortedFramebuffer(FBO_WIDTH,FBO_HEIGHT,1, InternalOutputSurface.DEPTH_NO_STENCIL);
484
       mFramebuffer.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
485
       }
486

    
487
     mFramebuffer.detachAll();
488
     mFramebuffer.attach(node);
489

    
490
     Static1D halo = new Static1D(5);
491
     Static4D color = new Static4D(0,0,0,1);
492
     PostprocessEffectBorder border = new PostprocessEffectBorder(halo,color);
493
     border.setHaloDepth(false);
494
     effects.apply(border);
495

    
496
     final String name = object.getShortName()+".png";
497
     File file = new File(act.getFilesDir(), name);
498
     String filename = file.getAbsolutePath();
499

    
500
     mSaveIcon = 0;
501
     mPath = filename;
502
     }
503

    
504
///////////////////////////////////////////////////////////////////////////////////////////////////
505

    
506
   private void renderIcon(long time)
507
     {
508
     mFramebuffer.render(time);
509
     }
510

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

    
513
   private void saveIcon()
514
     {
515
     int fW = mFramebuffer.getWidth();
516
     int fH = mFramebuffer.getHeight();
517

    
518
     ByteBuffer buf = ByteBuffer.allocateDirect(fW*fH*4);
519
     buf.order(ByteOrder.LITTLE_ENDIAN);
520

    
521
     mFramebuffer.setAsReadFramebuffer(0);
522
     GLES31.glReadBuffer(GLES31.GL_COLOR_ATTACHMENT0);
523
     GLES31.glReadPixels( 0, 0, fW, fH, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, buf);
524
     BandagedCreatorWorkerThread.newBuffer(buf,fW,fH,6,mPath);
525
     GLES31.glBindFramebuffer(GLES31.GL_READ_FRAMEBUFFER, 0);
526

    
527
     mSaveIcon = -1;
528
     }
529

    
530
///////////////////////////////////////////////////////////////////////////////////////////////////
531

    
532
   public void displaySavingDialog()
533
     {
534
     BandagedCreatorActivity act = (BandagedCreatorActivity)mView.getContext();
535
     RubikDialogBandagedSave saveDiag = new RubikDialogBandagedSave();
536
     saveDiag.show(act.getSupportFragmentManager(), null);
537
     }
538

    
539
///////////////////////////////////////////////////////////////////////////////////////////////////
540

    
541
   public void setupReset()
542
     {
543
     mResettingObject = true;
544
     mInitialPhase    = true;
545
     mStartTime       = System.currentTimeMillis();
546
     }
547

    
548
///////////////////////////////////////////////////////////////////////////////////////////////////
549

    
550
   public boolean continueResetting(long time)
551
     {
552
     long diff = time-mStartTime;
553
     float quotient = ((float)diff)/DURATION;
554

    
555
     if( mInitialPhase && quotient>0.5f )
556
       {
557
       mInitialPhase=false;
558
       resetObject();
559
       }
560

    
561
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
562

    
563
     float sinA = (float)Math.sin(angle);
564
     float cosA = (float)Math.cos(angle);
565

    
566
     mQuatT.set(0, -sinA, 0, cosA);
567

    
568
     return quotient>1.0f;
569
     }
570

    
571
///////////////////////////////////////////////////////////////////////////////////////////////////
572

    
573
  public void touchCubit(int index)
574
    {
575
    mCubits[index].setMarked();
576
    }
577

    
578
///////////////////////////////////////////////////////////////////////////////////////////////////
579

    
580
  public void untouchCubit(int index)
581
    {
582
    mCubits[index].setUnmarked();
583
    }
584
}
(3-3/13)