Project

General

Profile

« Previous | Next » 

Revision 0c52af30

Added by Leszek Koltunski about 5 years ago

  • ID 0c52af30407546044c46ad8524ee9e2b5ea0193c
  • Child 8197c92d

New module: Rubik App. Initial commit.

View differences:

.gitignore
1
/build
build.gradle
1
apply plugin: 'com.android.application'
2

  
3
android {
4
    compileSdkVersion 27
5

  
6
    defaultConfig {
7
        applicationId "org.distorted.magic"
8
        minSdkVersion 24
9
        targetSdkVersion 27
10
        versionCode 1
11
        versionName "1.0"
12
    }
13

  
14
    buildTypes {
15
        release {
16
            minifyEnabled false
17
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
18
        }
19
    }
20

  
21
}
22

  
23
dependencies {
24
    implementation fileTree(dir: 'libs', include: ['*.jar'])
25

  
26
    api project(':distorted-library')
27
    implementation 'com.android.support:appcompat-v7:27.1.1'
28
}
distorted-cube.iml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<module external.linked.project.id=":distorted-cube" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
3
  <component name="FacetManager">
4
    <facet type="android-gradle" name="Android-Gradle">
5
      <configuration>
6
        <option name="GRADLE_PROJECT_PATH" value=":distorted-cube" />
7
      </configuration>
8
    </facet>
9
    <facet type="android" name="Android">
10
      <configuration>
11
        <option name="SELECTED_BUILD_VARIANT" value="debug" />
12
        <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
13
        <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
14
        <afterSyncTasks>
15
          <task>generateDebugSources</task>
16
        </afterSyncTasks>
17
        <option name="ALLOW_USER_CONFIGURATION" value="false" />
18
        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
19
        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
20
        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/rs/debug;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
21
        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
22
      </configuration>
23
    </facet>
24
  </component>
25
  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
26
    <output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
27
    <output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
28
    <exclude-output />
29
    <content url="file://$MODULE_DIR$">
30
      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
31
      <sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
32
      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
33
      <sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
34
      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
35
      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
36
      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
37
      <sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
38
      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
39
      <sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
40
      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
41
      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
42
      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
43
      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
44
      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
45
      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
46
      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
47
      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
48
      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
49
      <sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
50
      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
51
      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
52
      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
53
      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
54
      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
55
      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
56
      <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
57
      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
58
      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
59
      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
60
      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
61
      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
62
      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
63
      <sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
64
      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
65
      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
66
      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
67
      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
68
      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
69
      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
70
      <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
71
      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
72
      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
73
      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
74
      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
75
      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
76
      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
77
      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
78
      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
79
      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
80
      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
81
      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
82
      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
83
      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
84
      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
85
      <excludeFolder url="file://$MODULE_DIR$/build/generated/not_namespaced_r_class_sources" />
86
      <excludeFolder url="file://$MODULE_DIR$/build/generated/source/r" />
87
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotation_processor_list" />
88
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
89
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
90
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
91
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
92
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundle_manifest" />
93
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/check_manifest_result" />
94
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/compatible_screen_manifest" />
95
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
96
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
97
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
98
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-apk" />
99
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_app_manifest" />
100
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_app_info_output_file" />
101
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_main_apk_resources" />
102
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_merged_manifests" />
103
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_split_apk_resources" />
104
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
105
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
106
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint_jar" />
107
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
108
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
109
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
110
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/metadata_feature_manifest" />
111
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
112
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/processed_res" />
113
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
114
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
115
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
116
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
117
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
118
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
119
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/signing_config" />
120
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
121
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
122
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
123
      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/validate_signing_config" />
124
      <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
125
      <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
126
    </content>
127
    <orderEntry type="jdk" jdkName="Android API 27 Platform" jdkType="Android SDK" />
128
    <orderEntry type="sourceFolder" forTests="false" />
129
    <orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable:27.1.1@aar" level="project" />
130
    <orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core:1.1.0@aar" level="project" />
131
    <orderEntry type="library" name="Gradle: com.android.support:support-core-utils:27.1.1@aar" level="project" />
132
    <orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime:1.1.0@aar" level="project" />
133
    <orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.0@jar" level="project" />
134
    <orderEntry type="library" name="Gradle: com.android.support:support-annotations:27.1.1@jar" level="project" />
135
    <orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel:1.1.0@aar" level="project" />
136
    <orderEntry type="library" name="Gradle: com.android.support:support-core-ui:27.1.1@aar" level="project" />
137
    <orderEntry type="library" name="Gradle: com.android.support:support-compat:27.1.1@aar" level="project" />
138
    <orderEntry type="library" name="Gradle: android.arch.core:runtime:1.1.0@aar" level="project" />
139
    <orderEntry type="library" name="Gradle: com.android.support:support-fragment:27.1.1@aar" level="project" />
140
    <orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable:27.1.1@aar" level="project" />
141
    <orderEntry type="library" name="Gradle: com.android.support:appcompat-v7:27.1.1@aar" level="project" />
142
    <orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
143
    <orderEntry type="module" module-name="distorted-library" />
144
  </component>
145
</module>
proguard-rules.pro
1
# Add project specific ProGuard rules here.
2
# You can control the set of applied configuration files using the
3
# proguardFiles setting in build.gradle.
4
#
5
# For more details, see
6
#   http://developer.android.com/guide/developing/tools/proguard.html
7

  
8
# If your project uses WebView with JS, uncomment the following
9
# and specify the fully qualified class name to the JavaScript interface
10
# class:
11
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12
#   public *;
13
#}
14

  
15
# Uncomment this to preserve the line number information for
16
# debugging stack traces.
17
#-keepattributes SourceFile,LineNumberTable
18

  
19
# If you keep the line number information, uncomment this to
20
# hide the original source file name.
21
#-renamesourcefileattribute SourceFile
src/main/AndroidManifest.xml
1
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
    package="org.distorted.magic">
3

  
4
    <uses-feature android:glEsVersion="0x00030001" android:required="true" />
5

  
6
    <application
7
        android:allowBackup="true"
8
        android:icon="@mipmap/icon"
9
        android:label="@string/app_name"
10
        android:supportsRtl="true"
11
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
12

  
13
        <activity android:name=".RubikActivity">
14
            <intent-filter>
15
                <action android:name="android.intent.action.MAIN" />
16
                <category android:name="android.intent.category.LAUNCHER" />
17
            </intent-filter>
18
        </activity>
19
    </application>
20
</manifest>
src/main/java/org/distorted/magic/RubikActivity.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted 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
// Distorted 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 Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.magic;
21

  
22
import android.app.Activity;
23
import android.graphics.PorterDuff;
24
import android.graphics.drawable.Drawable;
25
import android.opengl.GLSurfaceView;
26
import android.os.Bundle;
27
import android.support.v4.content.ContextCompat;
28
import android.view.View;
29

  
30
import org.distorted.library.main.Distorted;
31

  
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33

  
34
public class RubikActivity extends Activity
35
{
36
            static final int DEFAULT_SIZE  = 3;
37
    private static final int STARTING_SIZE = 2;
38
    private static final int[] button_ids  = {R.id.rubikSize2, R.id.rubikSize3, R.id.rubikSize4};
39

  
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

  
42
    @Override
43
    protected void onCreate(Bundle icicle)
44
      {
45
      super.onCreate(icicle);
46
      setContentView(R.layout.layout);
47

  
48
      markButton(DEFAULT_SIZE);
49
      }
50

  
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52
    
53
    @Override
54
    protected void onPause() 
55
      {
56
      GLSurfaceView view = findViewById(R.id.rubikSurfaceView);
57
      view.onPause();
58
      Distorted.onPause();
59
      super.onPause();
60
      }
61

  
62
///////////////////////////////////////////////////////////////////////////////////////////////////
63
    
64
    @Override
65
    protected void onResume() 
66
      {
67
      super.onResume();
68
      GLSurfaceView view = findViewById(R.id.rubikSurfaceView);
69
      view.onResume();
70
      }
71
    
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73
    
74
    @Override
75
    protected void onDestroy() 
76
      {
77
      Distorted.onDestroy();  
78
      super.onDestroy();
79
      }
80

  
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82

  
83
    public void Scramble(View v)
84
      {
85
      RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
86
      view.scrambleCube();
87
      }
88

  
89
///////////////////////////////////////////////////////////////////////////////////////////////////
90

  
91
    public void Credits(View v)
92
      {
93
      android.util.Log.e("rubik", "credits...");
94
      }
95

  
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97

  
98
    public void setSize(View v)
99
      {
100
      int size=0, id = v.getId();
101

  
102
      for(int b=0; b<button_ids.length; b++)
103
        if( button_ids[b] == id )
104
          {
105
          size = b+STARTING_SIZE;
106
          break;
107
          }
108

  
109
      markButton(size);
110

  
111
      RubikSurfaceView view = findViewById(R.id.rubikSurfaceView);
112
      view.setNewCubeSize(size);
113
      }
114

  
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116

  
117
   private void markButton(int size)
118
     {
119
     for(int b=0; b<button_ids.length; b++)
120
       {
121
       Drawable d = findViewById(button_ids[b]).getBackground();
122

  
123
       if( size == b+STARTING_SIZE )
124
         {
125
         d.setColorFilter(ContextCompat.getColor(this,R.color.red), PorterDuff.Mode.MULTIPLY);
126
         }
127
       else
128
         {
129
         d.clearColorFilter();
130
         }
131
       }
132
     }
133
}
src/main/java/org/distorted/magic/RubikCube.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted 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
// Distorted 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 Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.magic;
21

  
22
import android.graphics.Bitmap;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

  
26
import org.distorted.library.effect.MatrixEffectMove;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
28
import org.distorted.library.effect.MatrixEffectRotate;
29
import org.distorted.library.effect.MatrixEffectScale;
30
import org.distorted.library.effect.VertexEffectSink;
31
import org.distorted.library.main.DistortedEffects;
32
import org.distorted.library.main.DistortedScreen;
33
import org.distorted.library.main.DistortedTexture;
34
import org.distorted.library.mesh.MeshCubes;
35
import org.distorted.library.message.EffectListener;
36
import org.distorted.library.type.Dynamic1D;
37
import org.distorted.library.type.Static1D;
38
import org.distorted.library.type.Static3D;
39
import org.distorted.library.type.Static4D;
40

  
41
///////////////////////////////////////////////////////////////////////////////////////////////////
42

  
43
class RubikCube
44
{
45
    private static final int POST_ROTATION_MILLISEC = 500;
46
    private static final int TEXTURE_SIZE = 100;
47

  
48
    private static final Static3D VectX = new Static3D(1,0,0);
49
    private static final Static3D VectY = new Static3D(0,1,0);
50
    private static final Static3D VectZ = new Static3D(0,0,1);
51

  
52
    private MeshCubes[][][] mCubes;
53
    private DistortedEffects[][][] mEffects;
54
    private Static4D[][][] mQuatScramble;
55
    private Static3D[][][] mRotationAxis;
56
    private Dynamic1D[][][] mRotationAngle;
57
    private Static3D[][][] mCurrentPosition;
58
    private Static1D mRotationAngleStatic, mRotationAngleMiddle, mRotationAngleFinal;
59
    private DistortedTexture mTexture;
60
    private DistortedEffects mEffectsListeningForNow;
61

  
62
    private int mRotAxis, mRotRow;
63
    private int mSize;
64

  
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

  
67
    RubikCube(int size, Static3D move, Static3D scale, Static4D quatC, Static4D quatA)
68
      {
69
      mSize = size;
70

  
71
      mRotationAngleStatic = new Static1D(0);
72
      mRotationAngleMiddle = new Static1D(0);
73
      mRotationAngleFinal  = new Static1D(0);
74

  
75
      mRotAxis= RubikSurfaceView.VECTX;
76
      mTexture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
77

  
78
      mCubes          = new MeshCubes[mSize][mSize][mSize];
79
      mEffects        = new DistortedEffects[mSize][mSize][mSize];
80
      mQuatScramble   = new Static4D[mSize][mSize][mSize];
81
      mRotationAxis   = new Static3D[mSize][mSize][mSize];
82
      mRotationAngle  = new Dynamic1D[mSize][mSize][mSize];
83
      mCurrentPosition= new Static3D[mSize][mSize][mSize];
84

  
85
      Static3D[][][] cubeVectors = new Static3D[mSize][mSize][mSize];
86

  
87
      Static3D center = new Static3D(TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f, TEXTURE_SIZE*0.5f);
88
      Static4D region = new Static4D(0,0,0, TEXTURE_SIZE*0.72f);
89

  
90
      VertexEffectSink        sinkEffect = new VertexEffectSink( new Static1D(getSinkStrength()), center, region );
91
      MatrixEffectMove        moveEffect = new MatrixEffectMove(move);
92
      MatrixEffectScale      scaleEffect = new MatrixEffectScale(scale);
93
      MatrixEffectQuaternion quatCEffect = new MatrixEffectQuaternion(quatC, center);
94
      MatrixEffectQuaternion quatAEffect = new MatrixEffectQuaternion(quatA, center);
95

  
96
      // 3x2 bitmap = 6 squares:
97
      //
98
      // RED     GREEN   BLUE
99
      // YELLOW  WHITE   BROWN
100

  
101
      final float ze = 0.0f;
102
      final float ot = 1.0f/3.0f;
103
      final float tt = 2.0f/3.0f;
104
      final float oh = 1.0f/2.0f;
105
      final float of = 1.0f/40.0f;
106

  
107
      final Static4D mapFront = new Static4D(ze,oh, ze+ot,oh+oh);
108
      final Static4D mapBack  = new Static4D(tt,ze, tt+ot,ze+oh);
109
      final Static4D mapLeft  = new Static4D(ot,ze, ot+ot,ze+oh);
110
      final Static4D mapRight = new Static4D(ze,ze, ze+ot,ze+oh);
111
      final Static4D mapTop   = new Static4D(tt,oh, tt+ot,oh+oh);
112
      final Static4D mapBottom= new Static4D(ot,oh, ot+ot,oh+oh);
113

  
114
      final Static4D mapBlack = new Static4D(ze,ze, ze+of,ze+of);
115

  
116
      Static4D tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom;
117
      float nc = 0.5f*(mSize-1);
118
      int vertices = (int)(24.0f/mSize + 2.0f);
119

  
120
      for(int x = 0; x< mSize; x++)
121
        for(int y = 0; y< mSize; y++)
122
          for(int z = 0; z< mSize; z++)
123
            {
124
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 ) // only the external walls
125
              {
126
              tmpLeft  = (x==       0 ? mapLeft  :mapBlack);
127
              tmpRight = (x== mSize-1 ? mapRight :mapBlack);
128
              tmpFront = (z== mSize-1 ? mapFront :mapBlack);
129
              tmpBack  = (z==       0 ? mapBack  :mapBlack);
130
              tmpTop   = (y== mSize-1 ? mapTop   :mapBlack);
131
              tmpBottom= (y==       0 ? mapBottom:mapBlack);
132

  
133
              mCubes[x][y][z]           = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
134
              cubeVectors[x][y][z]      = new Static3D( TEXTURE_SIZE*(x-nc), TEXTURE_SIZE*(y-nc), TEXTURE_SIZE*(z-nc) );
135
              mQuatScramble[x][y][z]    = new Static4D(0,0,0,1);
136
              mRotationAngle[x][y][z]   = new Dynamic1D();
137
              mRotationAxis[x][y][z]    = new Static3D(1,0,0);
138
              mCurrentPosition[x][y][z] = new Static3D(x,y,z);
139

  
140
              mEffects[x][y][z] = new DistortedEffects();
141
              mEffects[x][y][z].apply(sinkEffect);
142
              mEffects[x][y][z].apply(moveEffect);
143
              mEffects[x][y][z].apply(scaleEffect);
144
              mEffects[x][y][z].apply(quatCEffect);
145
              mEffects[x][y][z].apply(quatAEffect);
146
              mEffects[x][y][z].apply( new MatrixEffectRotate( mRotationAngle[x][y][z], mRotationAxis[x][y][z], center));
147
              mEffects[x][y][z].apply( new MatrixEffectQuaternion(mQuatScramble[x][y][z], center));
148
              mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
149
              }
150
            }
151
      }
152

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

  
155
    void attachToScreen(DistortedScreen screen)
156
      {
157
      for(int x=0; x<mSize; x++)
158
        for(int y=0; y<mSize; y++)
159
          for(int z=0; z<mSize; z++)
160
            {
161
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
162
              {
163
              screen.attach(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
164
              }
165
            }
166
      }
167

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

  
170
    void addNewRotation(int vector, float offset )
171
      {
172
      Static3D axis = VectX;
173

  
174
      switch(vector)
175
        {
176
        case RubikSurfaceView.VECTX: axis = VectX; break;
177
        case RubikSurfaceView.VECTY: axis = VectY; break;
178
        case RubikSurfaceView.VECTZ: axis = VectZ; break;
179
        }
180

  
181
      mRotAxis = vector;
182
      mRotRow  = (int)(mSize*offset);
183

  
184
      mRotationAngleStatic.set1(0.0f);
185

  
186
      for(int x=0; x<mSize; x++)
187
        for(int y=0; y<mSize; y++)
188
          for(int z=0; z<mSize; z++)
189
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
190
              {
191
              if( belongsToRotation(x,y,z,vector,mRotRow) )
192
                {
193
                mRotationAxis[x][y][z].set(axis);
194
                mRotationAngle[x][y][z].add(mRotationAngleStatic);
195
                }
196
              }
197
      }
198

  
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

  
201
    void continueRotation(float angleInDegrees)
202
      {
203
      mRotationAngleStatic.set1(angleInDegrees);
204
      }
205

  
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

  
208
    private int computeNearestAngle(float angle)
209
      {
210
      final int NEAREST = 90;
211

  
212
      int tmp = (int)((angle+NEAREST/2)/NEAREST);
213
      if( angle< -(NEAREST/2) ) tmp-=1;
214

  
215
      return NEAREST*tmp;
216
      }
217

  
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219

  
220
    void finishRotationCalledOnNextRender(EffectListener listener)
221
      {
222
      boolean first = true;
223
      float startingAngle = mRotationAngleStatic.get1();
224
      int nearestAngleInDegrees = computeNearestAngle(startingAngle);
225

  
226
      mRotationAngleFinal.set1(nearestAngleInDegrees);
227
      mRotationAngleMiddle.set1( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
228

  
229
      for(int x=0; x<mSize; x++)
230
        for(int y=0; y<mSize; y++)
231
          for(int z=0; z<mSize; z++)
232
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
233
              {
234
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
235
                {
236
                mRotationAngle[x][y][z].makeRunNowFor(POST_ROTATION_MILLISEC);
237
                mRotationAngle[x][y][z].add(mRotationAngleMiddle);
238
                mRotationAngle[x][y][z].add(mRotationAngleFinal);
239

  
240
                if( first )
241
                  {
242
                  first = false;
243
                  mEffectsListeningForNow = mEffects[x][y][z];
244
                  mEffectsListeningForNow.registerForMessages(listener);
245
                  }
246
                }
247
              }
248
      }
249

  
250
///////////////////////////////////////////////////////////////////////////////////////////////////
251

  
252
    void removeRotationCalledOnNextRender(EffectListener listener)
253
      {
254
      mEffectsListeningForNow.deregisterForMessages(listener);
255

  
256
      int nearestAngleInDegrees = computeNearestAngle(mRotationAngleStatic.get1());
257
      double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
258
      float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
259
      float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
260

  
261
      mRotationAngleStatic.set1(0);
262

  
263
      float qx=0,qy=0,qz=0;
264

  
265
      switch(mRotAxis)
266
        {
267
        case RubikSurfaceView.VECTX: qx=1; break;
268
        case RubikSurfaceView.VECTY: qy=1; break;
269
        case RubikSurfaceView.VECTZ: qz=1; break;
270
        }
271

  
272
      Static4D quat = new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
273

  
274
      for(int x=0; x<mSize; x++)
275
        for(int y=0; y<mSize; y++)
276
          for(int z=0; z<mSize; z++)
277
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
278
              {
279
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
280
                {
281
                mRotationAngle[x][y][z].makeRunNowFor(0);
282
                mRotationAngle[x][y][z].removeAll();
283
                mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z]));
284
                modifyCurrentPosition(x,y,z,quat);
285
                }
286
              }
287
      }
288

  
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

  
291
    private float getSinkStrength()
292
      {
293
      switch(mSize)
294
        {
295
        case 1 : return 1.1f;
296
        case 2 : return 1.5f;
297
        case 3 : return 1.8f;
298
        case 4 : return 2.0f;
299
        default: return 3.0f - 4.0f/mSize;
300
        }
301
      }
302

  
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

  
305
    private boolean belongsToRotation(int x, int y, int z, int vector, int row)
306
      {
307
      switch(vector)
308
        {
309
        case RubikSurfaceView.VECTX: return mCurrentPosition[x][y][z].get1()==row;
310
        case RubikSurfaceView.VECTY: return mCurrentPosition[x][y][z].get2()==row;
311
        case RubikSurfaceView.VECTZ: return mCurrentPosition[x][y][z].get3()==row;
312
        }
313

  
314
      return false;
315
      }
316

  
317
///////////////////////////////////////////////////////////////////////////////////////////////////
318

  
319
    private void modifyCurrentPosition(int x, int y, int z, Static4D quat)
320
      {
321
      Static3D current = mCurrentPosition[x][y][z];
322
      float diff = 0.5f*(mSize-1);
323
      float cubitCenterX = current.get1() - diff;
324
      float cubitCenterY = current.get2() - diff;
325
      float cubitCenterZ = current.get3() - diff;
326

  
327
      Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
328
      Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
329

  
330
      float rotatedX = rotatedCenter.get1() + diff;
331
      float rotatedY = rotatedCenter.get2() + diff;
332
      float rotatedZ = rotatedCenter.get3() + diff;
333

  
334
      int roundedX = (int)(rotatedX+0.1f);
335
      int roundedY = (int)(rotatedY+0.1f);
336
      int roundedZ = (int)(rotatedZ+0.1f);
337

  
338
      mCurrentPosition[x][y][z].set1(roundedX);
339
      mCurrentPosition[x][y][z].set2(roundedY);
340
      mCurrentPosition[x][y][z].set3(roundedZ);
341
      }
342

  
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344

  
345
    void createTexture()
346
      {
347
      Bitmap bitmap;
348

  
349
      final int S = 128;
350
      final int W = 3*S;
351
      final int H = 2*S;
352
      final int R = S/10;
353
      final int M = S/20;
354

  
355
      Paint paint = new Paint();
356
      bitmap = Bitmap.createBitmap(W,H, Bitmap.Config.ARGB_8888);
357
      Canvas canvas = new Canvas(bitmap);
358

  
359
      paint.setAntiAlias(true);
360
      paint.setTextAlign(Paint.Align.CENTER);
361
      paint.setStyle(Paint.Style.FILL);
362

  
363
      // 3x2 bitmap = 6 squares:
364
      //
365
      // RED     GREEN   BLUE
366
      // YELLOW  WHITE   BROWN
367

  
368
      paint.setColor(0xff000000);                                  // BLACK BACKGROUND
369
      canvas.drawRect(0, 0, W, H, paint);                          //
370

  
371
      paint.setColor(0xffff0000);                                  // RED
372
      canvas.drawRoundRect(    M,   M,   S-M,   S-M, R, R, paint); //
373
      paint.setColor(0xff00ff00);                                  // GREEN
374
      canvas.drawRoundRect(  S+M,   M, 2*S-M,   S-M, R, R, paint); //
375
      paint.setColor(0xff0000ff);                                  // BLUE
376
      canvas.drawRoundRect(2*S+M,   M, 3*S-M,   S-M, R, R, paint); //
377
      paint.setColor(0xffffff00);                                  // YELLOW
378
      canvas.drawRoundRect(    M, S+M,   S-M, 2*S-M, R, R, paint); //
379
      paint.setColor(0xffffffff);                                  // WHITE
380
      canvas.drawRoundRect(  S+M, S+M, 2*S-M, 2*S-M, R, R, paint); //
381
      paint.setColor(0xffb5651d);                                  // BROWN
382
      canvas.drawRoundRect(2*S+M, S+M, 3*S-M, 2*S-M, R, R, paint); //
383

  
384
      mTexture.setTexture(bitmap);
385
      }
386

  
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

  
389
    float getTextureSize()
390
      {
391
      return TEXTURE_SIZE;
392
      }
393

  
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

  
396
    float getSize()
397
      {
398
      return mSize;
399
      }
400
}
src/main/java/org/distorted/magic/RubikRenderer.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted 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
// Distorted 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 Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.magic;
21

  
22
import android.opengl.GLSurfaceView;
23

  
24
import org.distorted.library.effect.VertexEffectSink;
25
import org.distorted.library.main.Distorted;
26
import org.distorted.library.main.DistortedScreen;
27
import org.distorted.library.message.EffectListener;
28
import org.distorted.library.message.EffectMessage;
29
import org.distorted.library.type.Static3D;
30
import org.distorted.library.type.Static4D;
31

  
32
import javax.microedition.khronos.egl.EGLConfig;
33
import javax.microedition.khronos.opengles.GL10;
34

  
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36

  
37
class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
38
{
39
    private static final float CUBE_SCREEN_RATIO = 0.5f;
40
    private static final float CAMERA_DISTANCE   = 0.6f;  // 0.6 of the length of max(scrHeight,scrWidth)
41

  
42
    private RubikSurfaceView mView;
43
    private DistortedScreen mScreen;
44
    private Static3D mMove, mScale;
45
    private Static4D mQuatCurrent, mQuatAccumulated;
46
    private Static4D mTempCurrent, mTempAccumulated;
47
    private float mCubeSizeInScreenSpace;
48
    private boolean mFinishRotation, mRemoveRotation, mFinishDragCurrent, mFinishDragAccumulated;
49
    private boolean mCanRotate;
50
    private RubikCube mCube;
51

  
52
///////////////////////////////////////////////////////////////////////////////////////////////////
53

  
54
    RubikRenderer(RubikSurfaceView v)
55
      {
56
      mView = v;
57

  
58
      mScreen = new DistortedScreen();
59

  
60
      mTempCurrent     = new Static4D(0,0,0,1);
61
      mTempAccumulated = initializeQuat();
62
      mQuatCurrent     = new Static4D(0,0,0,1);
63
      mQuatAccumulated = initializeQuat();
64

  
65
      mMove  = new Static3D(0,0,0);
66
      mScale = new Static3D(1,1,1);
67

  
68
      mFinishRotation        = false;
69
      mRemoveRotation        = false;
70
      mFinishDragCurrent     = false;
71
      mFinishDragAccumulated = false;
72

  
73
      mCanRotate = true;
74

  
75
      mCube = new RubikCube( RubikActivity.DEFAULT_SIZE, mMove, mScale, mQuatCurrent, mQuatAccumulated);
76
      }
77

  
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79
// various things are done here delayed, 'after the next render' as not to be done mid-render and
80
// cause artifacts.
81

  
82
    public void onDrawFrame(GL10 glUnused) 
83
      {
84
      mScreen.render( System.currentTimeMillis() );
85

  
86
      if( mFinishDragCurrent )
87
        {
88
        mFinishDragCurrent = false;
89
        mQuatCurrent.set(mTempCurrent);
90
        }
91

  
92
      if( mFinishDragAccumulated )
93
        {
94
        mFinishDragAccumulated = false;
95
        mQuatAccumulated.set(mTempAccumulated);
96
        }
97

  
98
      if( mFinishRotation )
99
        {
100
        mCanRotate = false;
101
        mFinishRotation=false;
102
        mCube.finishRotationCalledOnNextRender(this);
103
        }
104

  
105
      if( mRemoveRotation )
106
        {
107
        mRemoveRotation=false;
108
        mCube.removeRotationCalledOnNextRender(this);
109
        mCanRotate = true;
110
        }
111
      }
112

  
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114
// EffectListener. The library sends a message to us when it's time to call 'removeRotation'
115

  
116
   public void effectMessage(final EffectMessage em, final long effectID, final long objectID)
117
     {
118
     switch(em)
119
        {
120
        case EFFECT_FINISHED: mRemoveRotation = true; break;
121
        }
122
     }
123

  
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125
    
126
    public void onSurfaceChanged(GL10 glUnused, int width, int height) 
127
      {
128
      float cameraDistance = CAMERA_DISTANCE*(width>height ? width:height);
129
      float fovInDegrees   = computeFOV(cameraDistance,height);
130

  
131
      mScreen.setProjection( fovInDegrees, 0.1f);
132
      mView.setScreenSize(width,height);
133
      mView.setCameraDist(cameraDistance);
134

  
135
      mCubeSizeInScreenSpace = CUBE_SCREEN_RATIO*(width>height ? height:width);
136
      float texSize = mCube.getTextureSize();
137
      float scaleFactor = mCubeSizeInScreenSpace/(texSize*mCube.getSize());
138

  
139
      mMove.set( (width-scaleFactor*texSize)/2 , (height-scaleFactor*texSize)/2 , -scaleFactor*texSize/2 );
140
      mScale.set(scaleFactor,scaleFactor,scaleFactor);
141

  
142
      mScreen.resize(width, height);
143
      }
144

  
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146
    
147
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
148
      {
149
      mCube.createTexture();
150
      mScreen.detachAll();
151
      mCube.attachToScreen(mScreen);
152

  
153
      VertexEffectSink.enable();
154

  
155
      try
156
        {
157
        Distorted.onCreate(mView.getContext());
158
        }
159
      catch(Exception ex)
160
        {
161
        android.util.Log.e("Rubik", ex.getMessage() );
162
        }
163
      }
164

  
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

  
167
    private float computeFOV(float cameraDistance, int screenHeight)
168
      {
169
      double halfFOVInRadians = Math.atan( screenHeight/(2*cameraDistance) );
170
      return (float)(2*halfFOVInRadians*(180/Math.PI));
171
      }
172

  
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174
// no this will not race with onDrawFrame
175

  
176
    void finishRotation()
177
      {
178
      mFinishRotation = true;
179
      }
180

  
181
///////////////////////////////////////////////////////////////////////////////////////////////////
182

  
183
    float returnCubeSizeInScreenSpace()
184
      {
185
      return mCubeSizeInScreenSpace;
186
      }
187

  
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189

  
190
    boolean canRotate()
191
      {
192
      return mCanRotate;
193
      }
194

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

  
197
    RubikCube getCube()
198
      {
199
      return mCube;
200
      }
201

  
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203
// Initial rotation of the cube. Something semi-random that looks good.
204

  
205
    Static4D initializeQuat()
206
      {
207
      return new Static4D(-0.25189602f,0.3546389f,0.009657208f,0.90038127f);
208
      }
209

  
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211

  
212
    void setQuatCurrent(Static4D current)
213
      {
214
      mTempCurrent.set(current);
215
      mFinishDragCurrent = true;
216
      }
217

  
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219

  
220
    void setQuatAccumulated(Static4D accumulated)
221
      {
222
      mTempAccumulated.set(accumulated);
223
      mFinishDragAccumulated = true;
224
      }
225
}
src/main/java/org/distorted/magic/RubikSurfaceView.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted 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
// Distorted 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 Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

  
20
package org.distorted.magic;
21

  
22
import android.app.ActivityManager;
23
import android.content.Context;
24
import android.content.pm.ConfigurationInfo;
25
import android.opengl.GLSurfaceView;
26
import android.util.AttributeSet;
27
import android.view.MotionEvent;
28

  
29
import org.distorted.library.type.Static4D;
30

  
31
///////////////////////////////////////////////////////////////////////////////////////////////////
32

  
33
class RubikSurfaceView extends GLSurfaceView
34
{
35
    private final static int NONE   =-1;
36
    private final static int FRONT  = 0;  // has to be 6 consecutive ints
37
    private final static int BACK   = 1;  // FRONT ... BOTTOM
38
    private final static int LEFT   = 2;  //
39
    private final static int RIGHT  = 3;  //
40
    private final static int TOP    = 4;  //
41
    private final static int BOTTOM = 5;  //
42

  
43
    static final int VECTX = 0;  //
44
    static final int VECTY = 1;  // dont change this
45
    static final int VECTZ = 2;  //
46

  
47
    private static final int[] VECT = {VECTX,VECTY,VECTZ};
48

  
49
    private boolean mDragging, mBeginningRotation, mContinuingRotation;
50
    private int mX, mY;
51
    private Static4D mQuatCurrent, mQuatAccumulated;
52
    private int mRotationVect;
53
    private RubikRenderer mRenderer;
54
    private RubikCube mCube;
55

  
56
    private float[] mPoint, mCamera, mTouchPointCastOntoFace, mDiff, mTouchPoint; // all in screen space
57
    private int mLastTouchedFace;
58
    private int mScreenWidth, mScreenHeight, mScreenMin;
59
    private float mCameraDistance;
60

  
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62

  
63
    public RubikSurfaceView(Context context, AttributeSet attrs)
64
      {
65
      super(context,attrs);
66

  
67
      if(!isInEditMode())
68
        {
69
        mRotationVect = VECT[0];
70

  
71
        mPoint = new float[3];
72
        mCamera= new float[3];
73
        mDiff  = new float[3];
74
        mTouchPoint = new float[3];
75
        mTouchPointCastOntoFace = new float[3];
76

  
77
        mScreenWidth = mScreenHeight = mScreenMin = 0;
78

  
79
        mRenderer = new RubikRenderer(this);
80
        mCube = mRenderer.getCube();
81

  
82
        mQuatCurrent     = new Static4D(0,0,0,1);
83
        mQuatAccumulated = mRenderer.initializeQuat();
84

  
85
        final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
86
        final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
87
        setEGLContextClientVersion( (configurationInfo.reqGlEsVersion>>16) >= 3 ? 3:2 );
88
        setRenderer(mRenderer);
89
        }
90
      }
91

  
92
///////////////////////////////////////////////////////////////////////////////////////////////////
93

  
94
    public RubikRenderer getRenderer()
95
      {
96
      return mRenderer;
97
      }
98

  
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

  
101
    @Override
102
    public boolean onTouchEvent(MotionEvent event)
103
      {
104
      int action = event.getAction();
105
      int x = (int)event.getX();
106
      int y = (int)event.getY();
107

  
108
      switch(action)
109
         {
110
         case MotionEvent.ACTION_DOWN: mX = x;
111
                                       mY = y;
112
                                       mLastTouchedFace = faceTouched(x,y);
113

  
114
                                       if( mLastTouchedFace != NONE )
115
                                         {
116
                                         mDragging           = false;
117
                                         mBeginningRotation  = mRenderer.canRotate();
118
                                         mContinuingRotation = false;
119
                                         }
120
                                       else
121
                                         {
122
                                         mDragging           = true;
123
                                         mBeginningRotation  = false;
124
                                         mContinuingRotation = false;
125
                                         }
126
                                       break;
127
         case MotionEvent.ACTION_MOVE: if( mDragging )
128
                                         {
129
                                         mQuatCurrent.set(quatFromDrag(mX-x,mY-y));
130
                                         mRenderer.setQuatCurrent(mQuatCurrent);
131
                                         }
132
                                       if( mBeginningRotation )
133
                                         {
134
                                         int minimumDistToStartRotating = (mScreenMin*mScreenMin)/100;
135

  
136
                                         if( (mX-x)*(mX-x)+(mY-y)*(mY-y) > minimumDistToStartRotating )
137
                                           {
138
                                           addNewRotation(x,y);
139
                                           mBeginningRotation = false;
140
                                           mContinuingRotation= true;
141
                                           }
142
                                         }
143
                                       else if( mContinuingRotation )
144
                                         {
145
                                         continueRotation(x,y);
146
                                         }
147
                                       break;
148
         case MotionEvent.ACTION_UP  : if( mDragging )
149
                                         {
150
                                         mQuatAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated));
151
                                         mQuatCurrent.set(0f, 0f, 0f, 1f);
152
                                         mRenderer.setQuatCurrent(mQuatCurrent);
153
                                         mRenderer.setQuatAccumulated(mQuatAccumulated);
154
                                         }
155

  
156
                                       if( mContinuingRotation )
157
                                         {
158
                                         finishRotation();
159
                                         }
160

  
161
                                       break;
162
         }
163

  
164
      return true;
165
      }
166

  
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

  
169
    void setNewCubeSize(int newCubeSize)
170
      {
171
      android.util.Log.e("view", "new size="+newCubeSize);
172
      }
173

  
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175

  
176
    void scrambleCube()
177
      {
178
      android.util.Log.e("view", "scrambling...");
179
      }
180

  
181
///////////////////////////////////////////////////////////////////////////////////////////////////
182

  
183
    void setScreenSize(int width, int height)
184
      {
185
      mScreenWidth = width;
186
      mScreenHeight= height;
187

  
188
      mScreenMin = width<height ? width:height;
189
      }
190

  
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

  
193
    void setCameraDist(float distance)
194
      {
195
      mCameraDistance = distance;
196
      }
197

  
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

  
200
    private int faceTouched(int xTouch, int yTouch)
201
      {
202
      float cubeHalfSize= mRenderer.returnCubeSizeInScreenSpace()*0.5f;
203

  
204
      convertTouchPointToScreenSpace(xTouch,yTouch);
205
      convertCameraPointToScreenSpace();
206

  
207
      for(int face=FRONT; face<=BOTTOM; face++)
208
        {
209
        if( faceIsVisible(face,cubeHalfSize) )
210
          {
211
          castTouchPointOntoFace(face,cubeHalfSize, mTouchPointCastOntoFace);
212

  
213
          float qX= (mTouchPointCastOntoFace[0]+cubeHalfSize) / (2*cubeHalfSize);
214
          float qY= (mTouchPointCastOntoFace[1]+cubeHalfSize) / (2*cubeHalfSize);
215
          float qZ= (mTouchPointCastOntoFace[2]+cubeHalfSize) / (2*cubeHalfSize);
216

  
217
          if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return face;
218
          }
219
        }
220

  
221
      return NONE;
222
      }
223

  
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

  
226
    private void addNewRotation(int x, int y)
227
      {
228
      float cubeHalfSize= mRenderer.returnCubeSizeInScreenSpace()*0.5f;
229

  
230
      convertTouchPointToScreenSpace(x,y);
231
      castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize,mDiff);
232

  
233
      mDiff[0] -= mTouchPointCastOntoFace[0];
234
      mDiff[1] -= mTouchPointCastOntoFace[1];
235
      mDiff[2] -= mTouchPointCastOntoFace[2];
236

  
237
      int xAxis = retFaceXaxis(mLastTouchedFace);
238
      int yAxis = retFaceYaxis(mLastTouchedFace);
239
      mRotationVect = (isVertical( mDiff[xAxis], mDiff[yAxis]) ? VECT[xAxis]:VECT[yAxis]);
240
      float offset= (mTouchPointCastOntoFace[mRotationVect]+cubeHalfSize)/(2*cubeHalfSize);
241

  
242
      mTouchPoint[0] = mPoint[0];
243
      mTouchPoint[1] = mPoint[1];
244
      mTouchPoint[2] = mPoint[2];
245

  
246
      mCube.addNewRotation(mRotationVect,offset);
247
      }
248

  
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

  
251
    private boolean isVertical(float x, float y)
252
      {
253
      return (y>x) ? (y>=-x) : (y< -x);
254
      }
255

  
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257
// 240 --> moving finger from the middle of the vertical screen to the right edge will rotate a
258
// given face by 240/2 = 120 degrees.
259

  
260
    private void continueRotation(int x, int y)
261
      {
262
      convertTouchPointToScreenSpace(x,y);
263

  
264
      mDiff[0] = mPoint[0]-mTouchPoint[0];
265
      mDiff[1] = mPoint[1]-mTouchPoint[1];
266
      mDiff[2] = mPoint[2]-mTouchPoint[2];
267

  
268
      int xAxis= retFaceXaxis(mLastTouchedFace);
269
      int yAxis= retFaceYaxis(mLastTouchedFace);
270
      int sign = retFaceRotationSign(mLastTouchedFace);
271
      float angle = (mRotationVect==xAxis ? mDiff[yAxis] : -mDiff[xAxis]);
272

  
273
      mCube.continueRotation(240.0f*sign*angle/mScreenMin);
274
      }
275

  
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

  
278
    private void finishRotation()
279
      {
280
      mRenderer.finishRotation();
281
      }
282

  
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284
// return quat1*quat2
285

  
286
    static Static4D quatMultiply( Static4D quat1, Static4D quat2 )
287
      {
288
      float qx = quat1.get1();
289
      float qy = quat1.get2();
290
      float qz = quat1.get3();
291
      float qw = quat1.get4();
292

  
293
      float rx = quat2.get1();
294
      float ry = quat2.get2();
295
      float rz = quat2.get3();
296
      float rw = quat2.get4();
297

  
298
      float tx = rw*qx - rz*qy + ry*qz + rx*qw;
299
      float ty = rw*qy + rz*qx + ry*qw - rx*qz;
300
      float tz = rw*qz + rz*qw - ry*qx + rx*qy;
301
      float tw = rw*qw - rz*qz - ry*qy - rx*qx;
302

  
303
      return new Static4D(tx,ty,tz,tw);
304
      }
305

  
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307
// rotate 'vector' by quat^(-1)  ( i.e. return (quat^-1)*vector*quat )
308

  
309
    static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat)
310
      {
311
      float qx = quat.get1();
312
      float qy = quat.get2();
313
      float qz = quat.get3();
314
      float qw = quat.get4();
315

  
316
      Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw);
317
      Static4D tmp = quatMultiply(quatInverted,vector);
318

  
319
      return quatMultiply(tmp,quat);
320
      }
321

  
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323
// rotate 'vector' by quat  ( i.e. return quat*vector*(quat^-1) )
324

  
325
    static Static4D rotateVectorByQuat(Static4D vector, Static4D quat)
326
      {
327
      float qx = quat.get1();
328
      float qy = quat.get2();
329
      float qz = quat.get3();
330
      float qw = quat.get4();
331

  
332
      Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw);
333
      Static4D tmp = quatMultiply(quat,vector);
334

  
335
      return quatMultiply(tmp,quatInverted);
336
      }
337

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

  
340
    private Static4D quatFromDrag(float dragX, float dragY)
341
      {
342
      float axisX = dragY;  // inverted X and Y - rotation axis is
343
      float axisY = dragX;  // perpendicular to (dragX,dragY)   Why not (-dragY, dragX) ? because Y axis is also inverted!
344
      float axisZ = 0;
345
      float axisL = (float)Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
346

  
347
      if( axisL>0 )
348
        {
349
        axisX /= axisL;
350
        axisY /= axisL;
351
        axisZ /= axisL;
352

  
353
        float cosA = (float)Math.cos(axisL*Math.PI/mScreenMin);
354
        float sinA = (float)Math.sqrt(1-cosA*cosA);
355

  
356
        return new Static4D(axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
357
        }
358

  
359
      return new Static4D(0f, 0f, 0f, 1f);
360
      }
361

  
362
///////////////////////////////////////////////////////////////////////////////////////////////////
363

  
364
    private boolean faceIsVisible(int face, float cubeHalfSize)
365
      {
366
      int sign = retFaceSign(face);
367
      int zAxis= retFaceZaxis(face);
368

  
369
      return sign*mCamera[zAxis] > cubeHalfSize;
370
      }
371

  
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373

  
374
    private void convertTouchPointToScreenSpace(int x, int y)
375
      {
376
      float halfScrWidth  = mScreenWidth *0.5f;
377
      float halfScrHeight = mScreenHeight*0.5f;
378
      Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0);
379
      Static4D rotatedTouchPoint= rotateVectorByInvertedQuat(touchPoint, mQuatAccumulated);
380

  
381
      mPoint[0] = rotatedTouchPoint.get1();
382
      mPoint[1] = rotatedTouchPoint.get2();
383
      mPoint[2] = rotatedTouchPoint.get3();
384
      }
385

  
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387

  
388
    private void convertCameraPointToScreenSpace()
389
      {
390
      Static4D cameraPoint = new Static4D(0, 0, mCameraDistance, 0);
391
      Static4D rotatedCamera= rotateVectorByInvertedQuat(cameraPoint, mQuatAccumulated);
392

  
393
      mCamera[0] = rotatedCamera.get1();
394
      mCamera[1] = rotatedCamera.get2();
395
      mCamera[2] = rotatedCamera.get3();
396
      }
397

  
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399
// given precomputed mCamera and mPoint, respectively camera and touch point positions in ScreenSpace,
400
// cast this touch point onto the surface defined by the 'face' and write the cast coords to 'output'.
401
// Center of the 'face' = (0,0), third coord always +- cubeHalfSize.
402

  
403
    private void castTouchPointOntoFace(int face, float cubeHalfSize, float[] output)
404
      {
405
      int sign = retFaceSign(face);
406
      int zAxis= retFaceZaxis(face);
407
      float diff = mPoint[zAxis]-mCamera[zAxis];
408

  
409
      float ratio =  diff!=0.0f ? (sign*cubeHalfSize-mCamera[zAxis])/diff : 0.0f;
410

  
411
      output[0] = (mPoint[0]-mCamera[0])*ratio + mCamera[0];
412
      output[1] = (mPoint[1]-mCamera[1])*ratio + mCamera[1];
413
      output[2] = (mPoint[2]-mCamera[2])*ratio + mCamera[2];
414
      }
415

  
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

  
418
    private int retFaceSign(int face)
419
      {
420
      return (face==FRONT || face==RIGHT || face==TOP) ? 1:-1;
421
      }
422

  
423
///////////////////////////////////////////////////////////////////////////////////////////////////
424

  
425
    private int retFaceRotationSign(int face)
426
      {
427
      return (face==BACK || face==RIGHT || face==TOP) ? 1:-1;
428
      }
429

  
430
///////////////////////////////////////////////////////////////////////////////////////////////////
431
// retFace{X,Y,Z}axis: 3 functions which return which real AXIS gets mapped to which when we look
432
// directly at a given face. For example, when we look at the RIGHT face of the cube (with TOP still
433
// in the top) then the 'real' X axis becomes the 'Z' axis, thus retFaceZaxis(RIGHT) = VECTX.
434

  
435
    private int retFaceXaxis(int face)
436
      {
437
      switch(face)
438
        {
439
        case FRONT :
440
        case BACK  : return VECTX;
441
        case LEFT  :
442
        case RIGHT : return VECTZ;
443
        case TOP   :
444
        case BOTTOM: return VECTX;
445
        }
446

  
447
      return -1;
448
      }
449

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

  
452
    private int retFaceYaxis(int face)
453
      {
454
      switch(face)
455
        {
456
        case FRONT :
457
        case BACK  : return VECTY;
458
        case LEFT  :
459
        case RIGHT : return VECTY;
460
        case TOP   :
461
        case BOTTOM: return VECTZ;
462
        }
463

  
464
      return -1;
465
      }
466

  
467
///////////////////////////////////////////////////////////////////////////////////////////////////
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff