Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorRenderer.java @ 6dff7924

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.PostprocessEffectBorder;
33
import org.distorted.library.main.DistortedEffects;
34
import org.distorted.library.main.DistortedFramebuffer;
35
import org.distorted.library.main.DistortedLibrary;
36
import org.distorted.library.main.DistortedNode;
37
import org.distorted.library.main.DistortedScreen;
38

    
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.json.JsonWriter;
45
import org.distorted.objectlib.main.ShapeHexahedron;
46
import org.distorted.objectlib.main.TwistyObject;
47
import org.distorted.objectlib.objects.TwistyBandagedGeneric;
48
import org.json.JSONException;
49

    
50
import java.io.File;
51
import java.io.FileNotFoundException;
52
import java.io.IOException;
53
import java.nio.ByteBuffer;
54
import java.nio.ByteOrder;
55

    
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57

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

    
63
   static final int COLOR_DEFAULT = 0xffffff55;
64
   static final int COLOR_MARKED  = 0xffff0000;
65

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

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

    
99
   private final BandagedCreatorView mView;
100
   private final DistortedScreen mScreen;
101
   private final Static3D mScale;
102
   private final BandagedCubit[] mCubits;
103
   private final Static4D mQuatT, mQuatA;
104

    
105
   private boolean mInitialPhase;
106
   private long mStartTime;
107
   private float mScaleValue;
108
   private float mX, mY, mZ, mW;
109
   private boolean mResetQuats, mSetQuatT, mResettingObject;
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

    
127
     mSaveIcon = -1;
128

    
129
     mScreen = new DistortedScreen();
130
     mScreen.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
131
     mScale = new Static3D(1,1,1);
132
     mCubits= createCubits();
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
     int len = POSITIONS.length;
160
     BandagedCubit[] cubits = new BandagedCubit[len];
161

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

    
167
     return cubits;
168
     }
169

    
170
///////////////////////////////////////////////////////////////////////////////////////////////////
171

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

    
176
     int len = POSITIONS.length;
177

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

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

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

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

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

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

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

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

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

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

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

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

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

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

    
260
      for(int i=0; i<len; i++)
261
        if( mCubits[i].isAttached() )
262
          {
263
          mCubits[i].scaleMove(mScaleValue);
264
          mCubits[i].setTexture( touched==i ? COLOR_MARKED : COLOR_DEFAULT);
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(26);
281

    
282
      DistortedLibrary.onSurfaceCreated(mView.getContext(),this,1);
283
      DistortedLibrary.setCull(true);
284
      }
285

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287

    
288
   public void distortedException(Exception ex)
289
     {
290
     android.util.Log.e("CREATOR", "unexpected exception: "+ex.getMessage() );
291
     }
292

    
293
///////////////////////////////////////////////////////////////////////////////////////////////////
294

    
295
   public BandagedCubit[] getCubits()
296
     {
297
     return mCubits;
298
     }
299

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

    
302
   public DistortedScreen getScreen()
303
     {
304
     return mScreen;
305
     }
306

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

    
309
   public void tryConnectingCubits(int index1, int index2)
310
     {
311
     if( index1!=index2 )
312
       {
313
       float[] pos1 = mCubits[index1].getPosition();
314
       float[] pos2 = mCubits[index2].getPosition();
315

    
316
       if( isAdjacent(pos1,pos2) )
317
         {
318
         mCubits[index2].join(pos1,mScaleValue);
319
         mCubits[index1].detach();
320
         mScreen.detach(mCubits[index1].getNode());
321
         }
322
       }
323
     }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326

    
327
   public Static4D getQuatAccu()
328
     {
329
     return mQuatA;
330
     }
331

    
332
///////////////////////////////////////////////////////////////////////////////////////////////////
333

    
334
   public void setQuatTemp(float x, float y, float z, float w)
335
     {
336
     mX = x;
337
     mY = y;
338
     mZ = z;
339
     mW = w;
340

    
341
     mSetQuatT = true;
342
     }
343

    
344
///////////////////////////////////////////////////////////////////////////////////////////////////
345

    
346
   public void resetQuats()
347
     {
348
     mResetQuats = true;
349
     }
350

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

    
353
   public boolean isBusy()
354
     {
355
     return mResettingObject;
356
     }
357

    
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359

    
360
   public void saveObject()
361
     {
362
     int len = POSITIONS.length;
363
     int numAttached=0;
364

    
365
     for(int i=0; i<len; i++)
366
       if( mCubits[i].isAttached() ) numAttached++;
367

    
368
     float[][] pos = new float[numAttached][];
369
     int attached=0;
370

    
371
     for(int i=0; i<len; i++)
372
       if( mCubits[i].isAttached() )
373
         {
374
         pos[attached++] = mCubits[i].getPosition();
375
         }
376

    
377
     TwistyBandagedGeneric.setPositions(pos);
378
     TwistyObject obj = new TwistyBandagedGeneric( new Static4D(0,0,0,1), 1.0f, TwistyObject.MODE_NORM);
379
     BandagedCreatorActivity act = (BandagedCreatorActivity) mView.getContext();
380

    
381
     boolean success = createObjectJson(obj,act);
382
     setupIconCreation(act);
383

    
384
     if( success )
385
       {
386
       act.addObject(obj.getShortName());
387
       }
388
     }
389

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

    
392
   private boolean createObjectJson(TwistyObject object, Activity act)
393
     {
394
     final String name = object.getShortName()+"_object.json";
395
     File file = new File(act.getFilesDir(), name);
396
     String filename = file.getAbsolutePath();
397

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

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

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

    
442
       return false;
443
       }
444
     }
445

    
446
///////////////////////////////////////////////////////////////////////////////////////////////////
447

    
448
   private void setupIconCreation(Activity act)
449
     {
450
     final float R=1.0f;
451
     final int FBO_WIDTH  = (int)(R*240);
452
     final int FBO_HEIGHT = (int)(R*360);
453
     final float OBJECT_SIZE = R*0.38f;
454

    
455
     TwistyObject object = new TwistyBandagedGeneric(ShapeHexahedron.DEFAULT_ROT, OBJECT_SIZE, TwistyObject.MODE_ICON);
456
     DistortedEffects effects = object.getObjectEffects();
457
     DistortedNode node = object.getNode();
458

    
459
     if( mFramebuffer==null )
460
       {
461
       mFramebuffer = new DistortedFramebuffer(FBO_WIDTH,FBO_HEIGHT,1, InternalOutputSurface.DEPTH_NO_STENCIL);
462
       mFramebuffer.glClearColor(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f);
463
       }
464

    
465
     mFramebuffer.detachAll();
466
     mFramebuffer.attach(node);
467

    
468
     Static1D halo = new Static1D(5);
469
     Static4D color = new Static4D(0,0,0,1);
470
     PostprocessEffectBorder border = new PostprocessEffectBorder(halo,color);
471
     border.setHaloDepth(false);
472
     effects.apply(border);
473

    
474
     final String name = object.getShortName()+".png";
475
     File file = new File(act.getFilesDir(), name);
476
     String filename = file.getAbsolutePath();
477

    
478
     mSaveIcon = 0;
479
     mPath = filename;
480
     }
481

    
482
///////////////////////////////////////////////////////////////////////////////////////////////////
483

    
484
   private void renderIcon(long time)
485
     {
486
     mFramebuffer.render(time);
487
     }
488

    
489
///////////////////////////////////////////////////////////////////////////////////////////////////
490

    
491
   private void saveIcon()
492
     {
493
     int fW = mFramebuffer.getWidth();
494
     int fH = mFramebuffer.getHeight();
495

    
496
     ByteBuffer buf = ByteBuffer.allocateDirect(fW*fH*4);
497
     buf.order(ByteOrder.LITTLE_ENDIAN);
498

    
499
     mFramebuffer.setAsReadFramebuffer(0);
500
     GLES31.glReadBuffer(GLES31.GL_COLOR_ATTACHMENT0);
501
     GLES31.glReadPixels( 0, 0, fW, fH, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, buf);
502
     BandagedCreatorWorkerThread.newBuffer(buf,fW,fH,6,mPath);
503
     GLES31.glBindFramebuffer(GLES31.GL_READ_FRAMEBUFFER, 0);
504

    
505
     mSaveIcon = -1;
506
     }
507

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

    
510
   public void displaySavingDialog()
511
     {
512
     BandagedCreatorActivity act = (BandagedCreatorActivity)mView.getContext();
513
     RubikDialogBandagedSave saveDiag = new RubikDialogBandagedSave();
514
     saveDiag.show(act.getSupportFragmentManager(), null);
515
     }
516

    
517
///////////////////////////////////////////////////////////////////////////////////////////////////
518

    
519
   public void setupReset()
520
     {
521
     mResettingObject = true;
522
     mInitialPhase    = true;
523
     mStartTime       = System.currentTimeMillis();
524
     }
525

    
526
///////////////////////////////////////////////////////////////////////////////////////////////////
527

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

    
533
     if( mInitialPhase && quotient>0.5f )
534
       {
535
       mInitialPhase=false;
536
       resetObject();
537
       }
538

    
539
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
540

    
541
     float sinA = (float)Math.sin(angle);
542
     float cosA = (float)Math.cos(angle);
543

    
544
     mQuatT.set(0, -sinA, 0, cosA);
545

    
546
     return quotient>1.0f;
547
     }
548
}
(3-3/13)