Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorRenderer.java @ 7cb8d4b0

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.RubikDialogSaveBandaged;
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

    
38
import org.distorted.library.type.Static1D;
39
import org.distorted.library.type.Static3D;
40
import org.distorted.library.type.Static4D;
41
import org.distorted.objectlib.json.JsonWriter;
42
import org.distorted.objectlib.main.ObjectControl;
43
import org.distorted.objectlib.main.ShapeHexahedron;
44
import org.distorted.objectlib.main.TwistyObject;
45
import org.distorted.objectlib.objects.TwistyBandagedGeneric;
46
import org.json.JSONException;
47

    
48
import java.io.File;
49
import java.io.FileNotFoundException;
50
import java.io.IOException;
51
import java.nio.ByteBuffer;
52
import java.nio.ByteOrder;
53

    
54
///////////////////////////////////////////////////////////////////////////////////////////////////
55

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

    
61
   static final int COLOR_DEFAULT = 0xffffff55;
62
   static final int COLOR_MARKED  = 0xffff0000;
63

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

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

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

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

    
112
///////////////////////////////////////////////////////////////////////////////////////////////////
113

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

    
119
     mView = v;
120

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

    
125
     mSaveIcon = -1;
126

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

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

    
165
     return cubits;
166
     }
167

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

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

    
174
     int len = POSITIONS.length;
175

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

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

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

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

    
204
     if( mResetQuats )
205
       {
206
       mResetQuats = false;
207

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

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

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

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

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

    
233
     if( mSaveIcon>=0 ) mSaveIcon++;
234
     if( mSaveIcon>=2 ) { saveIcon(); mSaveIcon = -1; }
235
     }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

    
239
   @Override
240
   public void onSurfaceChanged(GL10 glUnused, int width, int height)
241
      {
242
      final float Q = SCREEN_RATIO/OBJECT_SIZE;
243
      mScaleValue = width<height ? Q*width : Q*height;
244

    
245
      mScreen.detachAll();
246
      int len = POSITIONS.length;
247

    
248
      for(int i=0; i<len; i++)
249
        if( mCubits[i].isAttached() )
250
          {
251
          mCubits[i].scaleMove(mScaleValue);
252
          mCubits[i].setTexture(COLOR_DEFAULT);
253
          DistortedNode node = mCubits[i].getNode();
254
          mScreen.attach(node);
255
          }
256

    
257
      mScale.set( mScaleValue,mScaleValue,mScaleValue );
258
      mView.setScreenSize(width,height);
259
      mScreen.resize(width,height);
260
      }
261

    
262
///////////////////////////////////////////////////////////////////////////////////////////////////
263

    
264
   @Override
265
   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
266
      {
267
      DistortedLibrary.onSurfaceCreated(mView.getContext(),this,1);
268
      }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
   public void distortedException(Exception ex)
273
     {
274
     android.util.Log.e("CREATOR", "unexpected exception: "+ex.getMessage() );
275
     }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
   public BandagedCubit[] getCubits()
280
     {
281
     return mCubits;
282
     }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285

    
286
   public DistortedScreen getScreen()
287
     {
288
     return mScreen;
289
     }
290

    
291
///////////////////////////////////////////////////////////////////////////////////////////////////
292

    
293
   public void tryConnectingCubits(int index1, int index2)
294
     {
295
     if( index1!=index2 )
296
       {
297
       float[] pos1 = mCubits[index1].getPosition();
298
       float[] pos2 = mCubits[index2].getPosition();
299

    
300
       if( isAdjacent(pos1,pos2) )
301
         {
302
         mCubits[index2].join(pos1,mScaleValue);
303
         mCubits[index1].detach();
304
         mScreen.detach(mCubits[index1].getNode());
305
         }
306
       }
307
     }
308

    
309
///////////////////////////////////////////////////////////////////////////////////////////////////
310

    
311
   public Static4D getQuatAccu()
312
     {
313
     return mQuatA;
314
     }
315

    
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317

    
318
   public void setQuatTemp(float x, float y, float z, float w)
319
     {
320
     mX = x;
321
     mY = y;
322
     mZ = z;
323
     mW = w;
324

    
325
     mSetQuatT = true;
326
     }
327

    
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329

    
330
   public void resetQuats()
331
     {
332
     mResetQuats = true;
333
     }
334

    
335
///////////////////////////////////////////////////////////////////////////////////////////////////
336

    
337
   public boolean isBusy()
338
     {
339
     return mResettingObject;
340
     }
341

    
342
///////////////////////////////////////////////////////////////////////////////////////////////////
343

    
344
   public void saveObject()
345
     {
346
     int len = POSITIONS.length;
347
     int numAttached=0;
348

    
349
     for(int i=0; i<len; i++)
350
       if( mCubits[i].isAttached() ) numAttached++;
351

    
352
     float[][] pos = new float[numAttached][];
353
     int attached=0;
354

    
355
     for(int i=0; i<len; i++)
356
       if( mCubits[i].isAttached() )
357
         {
358
         pos[attached++] = mCubits[i].getPosition();
359
         }
360

    
361
     TwistyBandagedGeneric.setPositions(pos);
362
     TwistyObject obj = new TwistyBandagedGeneric();
363
     BandagedCreatorActivity act = (BandagedCreatorActivity) mView.getContext();
364

    
365
     boolean success = createObjectJson(obj,act);
366
     setupIconCreation(obj,act);
367

    
368
     if( success )
369
       {
370
       act.addObject(obj.getShortName());
371
       }
372
     }
373

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

    
376
   private boolean createObjectJson(TwistyObject object, Activity act)
377
     {
378
     final String name = object.getShortName()+"_object.json";
379
     File file = new File(act.getFilesDir(), name);
380
     String filename = file.getAbsolutePath();
381

    
382
     try
383
       {
384
       JsonWriter writer = JsonWriter.getInstance();
385
       String json = writer.createObjectString(object,24);
386
       writer.write(filename,json);
387
       return true;
388
       }
389
     catch(JSONException ex)
390
       {
391
       act.runOnUiThread(new Runnable()
392
         {
393
         public void run()
394
           {
395
           String message = "JSON Exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
396
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
397
           }
398
         });
399

    
400
       return false;
401
       }
402
     catch(FileNotFoundException ex)
403
       {
404
       act.runOnUiThread(new Runnable()
405
         {
406
         public void run()
407
           {
408
           String message = "FileNotFound exception saving to \n\n"+filename+"\n\n failed:\n\n"+ex.getMessage();
409
           Toast.makeText(act,message,Toast.LENGTH_LONG).show();
410
           }
411
         });
412

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

    
426
       return false;
427
       }
428
     }
429

    
430
///////////////////////////////////////////////////////////////////////////////////////////////////
431

    
432
   private void setupIconCreation(TwistyObject object, Activity act)
433
     {
434
/*
435
     // create framebuffer, attach object's node to it
436

    
437
     ObjectControl control = getControl();
438
     DistortedEffects effects = object.getObjectEffects();
439

    
440
     Static4D defRot = ShapeHexahedron.DEFAULT_ROT;
441
     Static1D halo = new Static1D(5);
442
     control.rotateNow(defRot);
443
     float scale = 1.15f;
444
     control.scaleNow(scale);
445
     Static4D color = new Static4D(0,0,0,1);
446
     PostprocessEffectBorder border = new PostprocessEffectBorder(halo,color);
447
     border.setHaloDepth(false);
448
     effects.apply(border);
449

    
450
     final String name = object.getShortName()+".png";
451
     File file = new File(act.getFilesDir(), name);
452
     String filename = file.getAbsolutePath();
453

    
454
     mSaveIcon = 0;
455
     mPath = filename;
456
 */
457
     }
458

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

    
461
    private void saveIcon()
462
      {
463
      int fW = mFramebuffer.getWidth();
464
      int fH = mFramebuffer.getHeight();
465
      ByteBuffer buf = ByteBuffer.allocateDirect(fW*fH*4);
466
      buf.order(ByteOrder.LITTLE_ENDIAN);
467

    
468
      int textureID = mFramebuffer.getTextureID();
469

    
470
      if( textureID>=0 )
471
        {
472
        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, textureID);
473
        GLES31.glReadPixels( 0, 0, fW, fH, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, buf);
474
        BandagedCreatorWorkerThread.newBuffer(buf,fW,fH,6,mPath);
475
        }
476
      else
477
        {
478
        android.util.Log.e("Save", "Error trying to read from offscreen FBO, textureID="+textureID);
479
        }
480

    
481
      mSaveIcon = -1;
482
      }
483

    
484
///////////////////////////////////////////////////////////////////////////////////////////////////
485

    
486
   public void displaySavingDialog()
487
     {
488
     BandagedCreatorActivity act = (BandagedCreatorActivity)mView.getContext();
489
     RubikDialogSaveBandaged saveDiag = new RubikDialogSaveBandaged();
490
     saveDiag.show(act.getSupportFragmentManager(), null);
491
     }
492

    
493
///////////////////////////////////////////////////////////////////////////////////////////////////
494

    
495
   public void setupReset()
496
     {
497
     mResettingObject = true;
498
     mInitialPhase    = true;
499
     mStartTime       = System.currentTimeMillis();
500
     }
501

    
502
///////////////////////////////////////////////////////////////////////////////////////////////////
503

    
504
   public boolean continueResetting(long time)
505
     {
506
     long diff = time-mStartTime;
507
     float quotient = ((float)diff)/DURATION;
508

    
509
     if( mInitialPhase && quotient>0.5f )
510
       {
511
       mInitialPhase=false;
512
       resetObject();
513
       }
514

    
515
     double angle = 2*Math.PI*quotient*quotient*(3-2*quotient);
516

    
517
     float sinA = (float)Math.sin(angle);
518
     float cosA = (float)Math.cos(angle);
519

    
520
     mQuatT.set(0, -sinA, 0, cosA);
521

    
522
     return quotient>1.0f;
523
     }
524
}
(3-3/13)