├── .gitignore ├── .idea ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── README.md-images └── Screenshot_1.png ├── app ├── build.gradle ├── libs │ └── EasyAR.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── aud │ │ ├── full │ │ │ ├── 307.jpg │ │ │ ├── 312.jpg │ │ │ ├── 314.jpg │ │ │ ├── 316.jpg │ │ │ └── 318.jpg │ │ ├── number │ │ │ ├── 307.jpg │ │ │ ├── 312.jpg │ │ │ ├── 314.jpg │ │ │ ├── 316.jpg │ │ │ └── 318.jpg │ │ └── shapes │ │ │ ├── 307.png │ │ │ ├── 312.png │ │ │ ├── 314.png │ │ │ ├── 316.png │ │ │ └── 318.png │ ├── fonts │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Italic.ttf │ │ ├── Roboto-LightItalic.ttf │ │ └── Roboto-Regular.ttf │ ├── json │ │ ├── full_sign_aud.json │ │ ├── number_sign_aud.json │ │ └── shapes_sign_aud.json │ └── teachers │ │ ├── Ананьев.jpg │ │ ├── Андреева.jpg │ │ ├── Боровцов.jpg │ │ ├── Кантор.jpg │ │ └── Крючкова.jpg │ ├── java │ └── com │ │ └── khoben │ │ └── samples │ │ └── studyar │ │ ├── AR │ │ ├── AR.java │ │ ├── ARUtils.java │ │ ├── MyAR.java │ │ └── Render │ │ │ ├── GLView.java │ │ │ ├── ImageRenderer.java │ │ │ └── TextureHelper.java │ │ ├── DatabaseHelper │ │ └── FirebaseHelper.java │ │ ├── ImageProcessing │ │ ├── ImagePool.java │ │ ├── ImageProcessing.java │ │ └── ObjectPool.java │ │ ├── Lesson.java │ │ ├── MainActivity.java │ │ ├── MyIterator │ │ ├── MyContainer.java │ │ ├── MyIterator.java │ │ └── TargetContainer.java │ │ └── Rubberstamp │ │ ├── PositionCalculator.java │ │ ├── RubberStamp.java │ │ ├── RubberStampConfig.java │ │ └── RubberStampPosition.java │ ├── jniLibs │ └── armeabi-v7a │ │ └── libEasyAR.so │ └── res │ ├── drawable │ ├── flashlight.xml │ ├── flashlight_off.xml │ ├── ic_search_black_24dp.xml │ └── transition.xml │ ├── layout │ └── activity_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── uml ├── desktop.ini ├── uml.png └── uml.vpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | # Uncomment the following line if you do not want to check your keystore files in. 45 | #*.jks 46 | 47 | # External native build folder generated in Android Studio 2.2 and later 48 | .externalNativeBuild 49 | 50 | # Google Services (e.g. APIs or Firebase) 51 | google-services.json 52 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 1.8 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # studyAR 2 | 3 | Course project on "Augmented Reality in the educational process" 4 | 5 | ## Built With 6 | 7 | * [EasyAR 2.0](https://www.easyar.com/view/download.html) - AR engine 8 | * [OpenGL ES 2.0](https://www.khronos.org/registry/OpenGL-Refpages/es2.0/) 9 | * [RubberStamp](https://github.com/vinaygaba/RubberStamp) - Used to output text on image 10 | 11 | ## Tests 12 | 13 | ![img1](https://github.com/khoben/studyAR/blob/master/README.md-images/Screenshot_1.png) 14 | -------------------------------------------------------------------------------- /README.md-images/Screenshot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/README.md-images/Screenshot_1.png -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | defaultConfig { 6 | applicationId "com.khoben.samples.studyar" 7 | minSdkVersion 21 8 | targetSdkVersion 25 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | compileOptions { 20 | sourceCompatibility JavaVersion.VERSION_1_8 21 | targetCompatibility JavaVersion.VERSION_1_8 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(include: ['*.jar'], dir: 'libs') 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | compile 'com.android.support:appcompat-v7:25.4.0' 31 | compile 'com.google.firebase:firebase-database:11.8.0' 32 | testCompile 'junit:junit:4.12' 33 | } 34 | 35 | 36 | apply plugin: 'com.google.gms.google-services' -------------------------------------------------------------------------------- /app/libs/EasyAR.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/libs/EasyAR.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\android\android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 23 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/assets/aud/full/307.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/full/307.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/full/312.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/full/312.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/full/314.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/full/314.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/full/316.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/full/316.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/full/318.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/full/318.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/number/307.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/number/307.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/number/312.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/number/312.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/number/314.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/number/314.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/number/316.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/number/316.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/number/318.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/number/318.jpg -------------------------------------------------------------------------------- /app/src/main/assets/aud/shapes/307.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/shapes/307.png -------------------------------------------------------------------------------- /app/src/main/assets/aud/shapes/312.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/shapes/312.png -------------------------------------------------------------------------------- /app/src/main/assets/aud/shapes/314.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/shapes/314.png -------------------------------------------------------------------------------- /app/src/main/assets/aud/shapes/316.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/shapes/316.png -------------------------------------------------------------------------------- /app/src/main/assets/aud/shapes/318.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/aud/shapes/318.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /app/src/main/assets/json/full_sign_aud.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "image": "aud/full/307.jpg", 5 | "name": "307" 6 | }, 7 | { 8 | "image": "aud/full/314.jpg", 9 | "name": "314" 10 | }, 11 | { 12 | "image": "aud/full/312.jpg", 13 | "name": "312" 14 | }, 15 | { 16 | "image": "aud/full/316.jpg", 17 | "name": "316" 18 | }, 19 | { 20 | "image": "aud/full/318.jpg", 21 | "name": "318" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/assets/json/number_sign_aud.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "image": "aud/number/307.jpg", 5 | "name": "307" 6 | }, 7 | { 8 | "image": "aud/number/314.jpg", 9 | "name": "314" 10 | }, 11 | { 12 | "image": "aud/number/312.jpg", 13 | "name": "312" 14 | }, 15 | { 16 | "image": "aud/number/316.jpg", 17 | "name": "316" 18 | }, 19 | { 20 | "image": "aud/number/318.jpg", 21 | "name": "318" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/assets/json/shapes_sign_aud.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "image": "aud/shapes/307.png", 5 | "name": "307" 6 | }, 7 | { 8 | "image": "aud/shapes/312.png", 9 | "name": "312" 10 | }, 11 | { 12 | "image": "aud/shapes/314.png", 13 | "name": "314" 14 | }, 15 | { 16 | "image": "aud/shapes/316.png", 17 | "name": "316" 18 | }, 19 | { 20 | "image": "aud/shapes/318.png", 21 | "name": "318" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/assets/teachers/Ананьев.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/teachers/Ананьев.jpg -------------------------------------------------------------------------------- /app/src/main/assets/teachers/Андреева.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/teachers/Андреева.jpg -------------------------------------------------------------------------------- /app/src/main/assets/teachers/Боровцов.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/teachers/Боровцов.jpg -------------------------------------------------------------------------------- /app/src/main/assets/teachers/Кантор.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/teachers/Кантор.jpg -------------------------------------------------------------------------------- /app/src/main/assets/teachers/Крючкова.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/assets/teachers/Крючкова.jpg -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/AR/AR.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.AR; 2 | 3 | import android.opengl.GLSurfaceView; 4 | 5 | /** 6 | * Created by extless on 07.01.2018. 7 | */ 8 | 9 | public interface AR { 10 | void initAR(); 11 | 12 | GLSurfaceView getGLView(); 13 | 14 | void setGLView(GLSurfaceView glView); 15 | 16 | boolean initialize(); 17 | 18 | boolean start(); 19 | 20 | boolean stop(); 21 | 22 | void dispose(); 23 | 24 | void initGL(); 25 | 26 | void resizeGL(int w, int h); 27 | 28 | void render(); 29 | 30 | boolean getFlashlightState(); 31 | 32 | void toogleFlashlightState(); 33 | 34 | void onResume(); 35 | 36 | void onPause(); 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/AR/ARUtils.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.AR; 2 | 3 | 4 | import android.util.Log; 5 | 6 | import cn.easyar.ImageTarget; 7 | import cn.easyar.ImageTracker; 8 | import cn.easyar.StorageType; 9 | 10 | 11 | public class ARUtils { 12 | private final static String TAG = "ARUtils"; 13 | 14 | public static void loadFromImage(ImageTracker tracker, String path) { 15 | ImageTarget target = new ImageTarget(); 16 | String jstr = "{\n" 17 | + " \"images\" :\n" 18 | + " [\n" 19 | + " {\n" 20 | + " \"image\" : \"" + path + "\",\n" 21 | + " \"name\" : \"" + path.substring(0, path.indexOf(".")) + "\"\n" 22 | + " }\n" 23 | + " ]\n" 24 | + "}"; 25 | target.setup(jstr, StorageType.Assets | StorageType.Json, ""); 26 | tracker.loadTarget(target, (target1, status) -> Log.i(TAG, String.format("load target (%b): %s (%d)", status, target1.name(), target1.runtimeID()))); 27 | } 28 | 29 | public static void loadFromJsonFile(ImageTracker tracker, String path, String targetname) { 30 | ImageTarget target = new ImageTarget(); 31 | target.setup(path, StorageType.Assets, targetname); 32 | tracker.loadTarget(target, (target1, status) -> Log.i(TAG, String.format("load target (%b): %s (%d)", status, target1.name(), target1.runtimeID()))); 33 | } 34 | 35 | public static void loadAllFromJsonFile(ImageTracker tracker, String path) { 36 | for (ImageTarget target : ImageTarget.setupAll(path, StorageType.Assets)) { 37 | tracker.loadTarget(target, (target1, status) -> Log.i(TAG, String.format("load target (%b): %s (%d)", status, target1.name(), target1.runtimeID()))); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/AR/MyAR.java: -------------------------------------------------------------------------------- 1 | //================================================================================================================================ 2 | // 3 | // Copyright (c) 2015-2017 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved. 4 | // EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China 5 | // and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd. 6 | // 7 | //================================================================================================================================ 8 | 9 | package com.khoben.samples.studyar.AR; 10 | 11 | import java.util.ArrayList; 12 | 13 | import android.graphics.Bitmap; 14 | import android.opengl.GLES20; 15 | import android.opengl.GLSurfaceView; 16 | import android.util.Log; 17 | import android.util.Pair; 18 | 19 | import com.google.firebase.database.DataSnapshot; 20 | import com.google.firebase.database.DatabaseError; 21 | import com.google.firebase.database.ValueEventListener; 22 | import com.khoben.samples.studyar.AR.Render.GLView; 23 | import com.khoben.samples.studyar.AR.Render.ImageRenderer; 24 | import com.khoben.samples.studyar.AR.Render.TextureHelper; 25 | import com.khoben.samples.studyar.DatabaseHelper.FirebaseHelper; 26 | import com.khoben.samples.studyar.ImageProcessing.ImagePool; 27 | import com.khoben.samples.studyar.ImageProcessing.ImageProcessing; 28 | import com.khoben.samples.studyar.Lesson; 29 | import com.khoben.samples.studyar.MainActivity; 30 | import com.khoben.samples.studyar.MyIterator.MyIterator; 31 | import com.khoben.samples.studyar.MyIterator.TargetContainer; 32 | 33 | import cn.easyar.CameraCalibration; 34 | import cn.easyar.CameraDevice; 35 | import cn.easyar.CameraDeviceFocusMode; 36 | import cn.easyar.CameraDeviceType; 37 | import cn.easyar.CameraFrameStreamer; 38 | import cn.easyar.Engine; 39 | import cn.easyar.Frame; 40 | import cn.easyar.ImageTarget; 41 | import cn.easyar.ImageTracker; 42 | import cn.easyar.Renderer; 43 | import cn.easyar.Target; 44 | import cn.easyar.TargetInstance; 45 | import cn.easyar.TargetStatus; 46 | import cn.easyar.Vec2I; 47 | import cn.easyar.Vec4I; 48 | 49 | 50 | public class MyAR implements AR { 51 | 52 | private final String TAG = "MyAR"; 53 | 54 | private static String key = "QjLaKui9g0HpqU2wzKEdmoCSMIrUIyh8LjZJz2JV" + 55 | "7qGXo80itvYjVzYco59Z3EVSMdGlC3OBJBgsbJ1bW4KJ0lzbAVE34SbjVz0lsEqG0ghnVuosGMnEqghEVARJzgkSsv137IphBLM21z9vVMlmoNagwCsVpejLAGy6um7PE6PRqx4Fn7oRtvQVJpu0u9ILEUqtQu2K"; 56 | 57 | private CameraDevice camera; 58 | private CameraFrameStreamer streamer; 59 | private ArrayList trackers; 60 | private Renderer videobgRenderer; 61 | private ImageRenderer imageRenderer; 62 | private boolean viewportChanged; 63 | private int rotation = 0; 64 | 65 | private final Vec2I cameraResolution = new Vec2I(1280, 720); 66 | private Vec2I viewSize = new Vec2I(0, 0); 67 | private Vec4I viewport = new Vec4I(0, 0, cameraResolution.data[0], cameraResolution.data[1]); 68 | 69 | private String currentTarget; 70 | private String previusTarget; 71 | 72 | private Lesson curLesson; 73 | 74 | private String PATH_TO_MARKERS = "json/%s_sign_aud.json"; 75 | private final String[] allTypes = { 76 | "shapes", 77 | "full", 78 | "number" 79 | }; 80 | 81 | private Bitmap bitmap; 82 | private ImageProcessing imageProcessing; 83 | private boolean isFlashlightEnabled; 84 | 85 | private GLSurfaceView glView; 86 | private MainActivity mainActivity; 87 | 88 | private ImagePool pairObjectPool; 89 | 90 | private static volatile MyAR instance; 91 | 92 | public static MyAR getInstance(MainActivity mainActivity) { 93 | MyAR localInstance = instance; 94 | if (localInstance == null) { 95 | synchronized (MyAR.class) { 96 | localInstance = instance; 97 | if (localInstance == null) { 98 | instance = localInstance = new MyAR(mainActivity); 99 | } 100 | } 101 | } 102 | return localInstance; 103 | } 104 | 105 | private MyAR(MainActivity mainActivity) { 106 | this.mainActivity = mainActivity; 107 | glView = new GLView(mainActivity, this); 108 | trackers = new ArrayList<>(); 109 | imageProcessing = new ImageProcessing(mainActivity); 110 | currentTarget = null; 111 | previusTarget = null; 112 | viewportChanged = false; 113 | isFlashlightEnabled = false; 114 | pairObjectPool = new ImagePool(mainActivity); 115 | } 116 | 117 | @Override 118 | public void initAR() { 119 | if (!Engine.initialize(mainActivity, key)) { 120 | Log.e(TAG, "Initialization Failed."); 121 | } 122 | } 123 | 124 | @Override 125 | public GLSurfaceView getGLView() { 126 | return glView; 127 | } 128 | 129 | @Override 130 | public void setGLView(GLSurfaceView glView) { 131 | this.glView = glView; 132 | } 133 | 134 | public boolean initialize() { 135 | camera = new CameraDevice(); 136 | streamer = new CameraFrameStreamer(); 137 | streamer.attachCamera(camera); 138 | 139 | boolean status = true; 140 | status &= camera.open(CameraDeviceType.Default); 141 | camera.setSize(cameraResolution); 142 | 143 | if (!status) { 144 | return status; 145 | } 146 | 147 | ImageTracker tracker = new ImageTracker(); 148 | tracker.attachStreamer(streamer); 149 | 150 | 151 | for (String type : allTypes) { 152 | ARUtils.loadAllFromJsonFile(tracker, String.format(PATH_TO_MARKERS, type)); 153 | } 154 | 155 | trackers.add(tracker); 156 | 157 | return status; 158 | } 159 | 160 | public void dispose() { 161 | for (ImageTracker tracker : trackers) { 162 | tracker.dispose(); 163 | } 164 | trackers.clear(); 165 | imageRenderer = null; 166 | if (videobgRenderer != null) { 167 | videobgRenderer.dispose(); 168 | videobgRenderer = null; 169 | } 170 | if (streamer != null) { 171 | streamer.dispose(); 172 | streamer = null; 173 | } 174 | if (camera != null) { 175 | camera.dispose(); 176 | camera = null; 177 | } 178 | } 179 | 180 | public boolean start() { 181 | boolean status = true; 182 | status &= (camera != null) && camera.start(); 183 | status &= (streamer != null) && streamer.start(); 184 | assert camera != null; 185 | camera.setFocusMode(CameraDeviceFocusMode.Continousauto); 186 | for (ImageTracker tracker : trackers) { 187 | status &= tracker.start(); 188 | } 189 | return status; 190 | } 191 | 192 | public boolean stop() { 193 | boolean status = true; 194 | for (ImageTracker tracker : trackers) { 195 | status &= tracker.stop(); 196 | } 197 | status &= (streamer != null) && streamer.stop(); 198 | status &= (camera != null) && camera.stop(); 199 | return status; 200 | } 201 | 202 | public void initGL() { 203 | if (videobgRenderer != null) { 204 | videobgRenderer.dispose(); 205 | } 206 | videobgRenderer = new Renderer(); 207 | imageRenderer = new ImageRenderer(); 208 | imageRenderer.init(); 209 | } 210 | 211 | public void resizeGL(int width, int height) { 212 | viewSize = new Vec2I(width, height); 213 | viewportChanged = true; 214 | } 215 | 216 | private void updateViewport() { 217 | CameraCalibration calib = camera != null ? camera.cameraCalibration() : null; 218 | int rotation = calib != null ? calib.rotation() : 0; 219 | if (rotation != this.rotation) { 220 | this.rotation = rotation; 221 | viewportChanged = true; 222 | } 223 | if (viewportChanged) { 224 | Vec2I size = new Vec2I(1, 1); 225 | if ((camera != null) && camera.isOpened()) { 226 | size = camera.size(); 227 | } 228 | if (rotation == 90 || rotation == 270) { 229 | size = new Vec2I(size.data[1], size.data[0]); 230 | } 231 | float scaleRatio = Math.max((float) viewSize.data[0] / (float) size.data[0], (float) viewSize.data[1] / (float) size.data[1]); 232 | Vec2I viewport_size = new Vec2I(Math.round(size.data[0] * scaleRatio), Math.round(size.data[1] * scaleRatio)); 233 | viewport = new Vec4I((viewSize.data[0] - viewport_size.data[0]) / 2, (viewSize.data[1] - viewport_size.data[1]) / 2, viewport_size.data[0], viewport_size.data[1]); 234 | 235 | if ((camera != null) && camera.isOpened()) 236 | viewportChanged = false; 237 | } 238 | } 239 | 240 | public void render() { 241 | GLES20.glClearColor(1.f, 1.f, 1.f, 1.f); 242 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 243 | 244 | if (videobgRenderer != null) { 245 | Vec4I default_viewport = new Vec4I(0, 0, viewSize.data[0], viewSize.data[1]); 246 | GLES20.glViewport(default_viewport.data[0], default_viewport.data[1], default_viewport.data[2], default_viewport.data[3]); 247 | if (videobgRenderer.renderErrorMessage(default_viewport)) { 248 | return; 249 | } 250 | } 251 | 252 | if (streamer == null) { 253 | return; 254 | } 255 | Frame frame = streamer.peek(); 256 | try { 257 | updateViewport(); 258 | GLES20.glViewport(viewport.data[0], viewport.data[1], viewport.data[2], viewport.data[3]); 259 | 260 | if (videobgRenderer != null) { 261 | videobgRenderer.render(frame, viewport); 262 | } 263 | 264 | TargetContainer targetContainer = new TargetContainer(frame.targetInstances()); 265 | MyIterator targetIterator = targetContainer.getIterator(); 266 | 267 | while (targetIterator.hasNext()) { 268 | TargetInstance targetInstance = (TargetInstance) targetIterator.next(); 269 | int status = targetInstance.status(); 270 | if (status == TargetStatus.Tracked) { 271 | Target target = targetInstance.target(); 272 | ImageTarget imagetarget = target instanceof ImageTarget ? (ImageTarget) (target) : null; 273 | if (imagetarget == null) { 274 | continue; 275 | } 276 | if (imageRenderer != null) { 277 | currentTarget = imagetarget.name(); 278 | if (!currentTarget.equals(previusTarget)) { 279 | Log.i(TAG, String.format("current: %s, prev: %s", currentTarget, previusTarget)); 280 | 281 | Lesson existingLesson = pairObjectPool.findExistingLesson(currentTarget); 282 | if (existingLesson == null) { 283 | FirebaseHelper.timetableReference.child(currentTarget).addListenerForSingleValueEvent(new ValueEventListener() { 284 | @Override 285 | public void onDataChange(DataSnapshot dataSnapshot) { 286 | 287 | curLesson = dataSnapshot.getValue(Lesson.class); 288 | new Thread(() -> { 289 | //bitmap = imageProcessing.generateBitmap(curLesson); 290 | bitmap = pairObjectPool.checkOut(curLesson).getBitmap(); 291 | TextureHelper.updateBitmap(bitmap); 292 | }).start(); 293 | Log.i(TAG, curLesson.toString()); 294 | } 295 | 296 | @Override 297 | public void onCancelled(DatabaseError databaseError) { 298 | Log.e(TAG, databaseError.getMessage()); 299 | } 300 | }); 301 | } else { 302 | bitmap = existingLesson.getBitmap(); 303 | TextureHelper.updateBitmap(bitmap); 304 | } 305 | } 306 | imageRenderer.render(camera.projectionGL(0.2f, 500.f), targetInstance.poseGL(), imagetarget.size()); 307 | } 308 | } 309 | previusTarget = currentTarget; 310 | } 311 | 312 | } finally { 313 | frame.dispose(); 314 | } 315 | } 316 | 317 | @Override 318 | public boolean getFlashlightState() { 319 | return isFlashlightEnabled; 320 | } 321 | 322 | @Override 323 | public void toogleFlashlightState() { 324 | isFlashlightEnabled = !isFlashlightEnabled; 325 | toogleFlashlight(isFlashlightEnabled); 326 | } 327 | 328 | @Override 329 | public void onResume() { 330 | glView.onResume(); 331 | } 332 | 333 | @Override 334 | public void onPause() { 335 | glView.onPause(); 336 | } 337 | 338 | public void toogleFlashlight(boolean on) { 339 | camera.setFlashTorchMode(on); 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/AR/Render/GLView.java: -------------------------------------------------------------------------------- 1 | //================================================================================================================================ 2 | // 3 | // Copyright (c) 2015-2017 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved. 4 | // EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China 5 | // and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd. 6 | // 7 | //================================================================================================================================ 8 | 9 | package com.khoben.samples.studyar.AR.Render; 10 | 11 | import javax.microedition.khronos.egl.EGL10; 12 | import javax.microedition.khronos.egl.EGLConfig; 13 | import javax.microedition.khronos.egl.EGLContext; 14 | import javax.microedition.khronos.egl.EGLDisplay; 15 | import javax.microedition.khronos.opengles.GL10; 16 | 17 | import android.content.Context; 18 | import android.opengl.GLSurfaceView; 19 | 20 | import com.khoben.samples.studyar.AR.AR; 21 | 22 | import cn.easyar.Engine; 23 | 24 | public class GLView extends GLSurfaceView { 25 | private AR myAR; 26 | 27 | public GLView(Context context, final AR myAR) { 28 | super(context); 29 | setEGLContextFactory(new ContextFactory()); 30 | setEGLConfigChooser(new ConfigChooser()); 31 | 32 | this.myAR = myAR; 33 | 34 | this.setRenderer(new GLSurfaceView.Renderer() { 35 | @Override 36 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 37 | synchronized (myAR) { 38 | myAR.initGL(); 39 | } 40 | } 41 | 42 | @Override 43 | public void onSurfaceChanged(GL10 gl, int w, int h) { 44 | synchronized (myAR) { 45 | myAR.resizeGL(w, h); 46 | } 47 | } 48 | 49 | @Override 50 | public void onDrawFrame(GL10 gl) { 51 | synchronized (myAR) { 52 | myAR.render(); 53 | } 54 | } 55 | }); 56 | this.setZOrderMediaOverlay(true); 57 | } 58 | 59 | @Override 60 | protected void onAttachedToWindow() { 61 | super.onAttachedToWindow(); 62 | synchronized (myAR) { 63 | if (myAR.initialize()) { 64 | myAR.start(); 65 | } 66 | } 67 | } 68 | 69 | @Override 70 | protected void onDetachedFromWindow() { 71 | synchronized (myAR) { 72 | myAR.stop(); 73 | myAR.dispose(); 74 | } 75 | super.onDetachedFromWindow(); 76 | } 77 | 78 | @Override 79 | public void onResume() { 80 | super.onResume(); 81 | Engine.onResume(); 82 | } 83 | 84 | @Override 85 | public void onPause() { 86 | Engine.onPause(); 87 | super.onPause(); 88 | } 89 | 90 | private static class ContextFactory implements GLSurfaceView.EGLContextFactory { 91 | private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 92 | 93 | public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { 94 | EGLContext context; 95 | int[] attrib = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; 96 | context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib); 97 | return context; 98 | } 99 | 100 | public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { 101 | egl.eglDestroyContext(display, context); 102 | } 103 | } 104 | 105 | private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { 106 | public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 107 | final int EGL_OPENGL_ES2_BIT = 0x0004; 108 | final int[] attrib = {EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4, 109 | EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE}; 110 | 111 | int[] num_config = new int[1]; 112 | egl.eglChooseConfig(display, attrib, null, 0, num_config); 113 | 114 | int numConfigs = num_config[0]; 115 | if (numConfigs <= 0) 116 | throw new IllegalArgumentException("fail to choose EGL configs"); 117 | 118 | EGLConfig[] configs = new EGLConfig[numConfigs]; 119 | egl.eglChooseConfig(display, attrib, configs, numConfigs, 120 | num_config); 121 | 122 | for (EGLConfig config : configs) { 123 | int[] val = new int[1]; 124 | int r = 0, g = 0, b = 0, a = 0, d = 0; 125 | if (egl.eglGetConfigAttrib(display, config, EGL10.EGL_DEPTH_SIZE, val)) 126 | d = val[0]; 127 | if (d < 16) 128 | continue; 129 | 130 | if (egl.eglGetConfigAttrib(display, config, EGL10.EGL_RED_SIZE, val)) 131 | r = val[0]; 132 | if (egl.eglGetConfigAttrib(display, config, EGL10.EGL_GREEN_SIZE, val)) 133 | g = val[0]; 134 | if (egl.eglGetConfigAttrib(display, config, EGL10.EGL_BLUE_SIZE, val)) 135 | b = val[0]; 136 | if (egl.eglGetConfigAttrib(display, config, EGL10.EGL_ALPHA_SIZE, val)) 137 | a = val[0]; 138 | if (r == 8 && g == 8 && b == 8 && a == 0) 139 | return config; 140 | } 141 | 142 | return configs[0]; 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/AR/Render/ImageRenderer.java: -------------------------------------------------------------------------------- 1 | //================================================================================================================================ 2 | // 3 | // Copyright (c) 2015-2017 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved. 4 | // EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China 5 | // and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd. 6 | // 7 | //================================================================================================================================ 8 | 9 | package com.khoben.samples.studyar.AR.Render; 10 | 11 | import android.opengl.GLES20; 12 | 13 | import java.nio.ByteBuffer; 14 | import java.nio.FloatBuffer; 15 | import java.nio.ShortBuffer; 16 | 17 | import cn.easyar.Vec2F; 18 | import cn.easyar.Matrix44F; 19 | 20 | public class ImageRenderer { 21 | private int shaderProgram; 22 | private int posCoord; 23 | private int posTex; 24 | private int posTrans; 25 | private int posProj; 26 | 27 | private int vboCoord; 28 | private int vboTex; 29 | private int vboFaces; 30 | 31 | private final String TAG = "ImageRenderer"; 32 | 33 | private final String vertexShaderProgram = "uniform mat4 trans;\n" 34 | + "uniform mat4 proj;\n" 35 | + "attribute vec4 coord;\n" 36 | + "attribute vec2 texcoord;\n" 37 | + "varying vec2 vtexcoord;\n" 38 | + "\n" 39 | + "void main(void)\n" 40 | + "{\n" 41 | + " vtexcoord = texcoord;\n" 42 | + " gl_Position = proj*trans*coord;\n" 43 | + "}\n" 44 | + "\n"; 45 | 46 | private final String fragmentShaderProgram = "#ifdef GL_ES\n" 47 | + "precision highp float;\n" 48 | + "#endif\n" 49 | + "varying vec2 vtexcoord;\n" 50 | + "uniform sampler2D texture;\n" 51 | + "\n" 52 | + "void main(void)\n" 53 | + "{\n" 54 | + " gl_FragColor = texture2D(texture, vtexcoord);\n" 55 | + "}\n" 56 | + "\n"; 57 | 58 | private float[] flatten(float[][] a) { 59 | int size = 0; 60 | for (int k = 0; k < a.length; k += 1) { 61 | size += a[k].length; 62 | } 63 | float[] l = new float[size]; 64 | int offset = 0; 65 | for (int k = 0; k < a.length; k += 1) { 66 | System.arraycopy(a[k], 0, l, offset, a[k].length); 67 | offset += a[k].length; 68 | } 69 | return l; 70 | } 71 | 72 | private int[] flatten(int[][] a) { 73 | int size = 0; 74 | for (int k = 0; k < a.length; k += 1) { 75 | size += a[k].length; 76 | } 77 | int[] l = new int[size]; 78 | int offset = 0; 79 | for (int k = 0; k < a.length; k += 1) { 80 | System.arraycopy(a[k], 0, l, offset, a[k].length); 81 | offset += a[k].length; 82 | } 83 | return l; 84 | } 85 | 86 | private short[] flatten(short[][] a) { 87 | int size = 0; 88 | for (int k = 0; k < a.length; k += 1) { 89 | size += a[k].length; 90 | } 91 | short[] l = new short[size]; 92 | int offset = 0; 93 | for (int k = 0; k < a.length; k += 1) { 94 | System.arraycopy(a[k], 0, l, offset, a[k].length); 95 | offset += a[k].length; 96 | } 97 | return l; 98 | } 99 | 100 | private byte[] flatten(byte[][] a) { 101 | int size = 0; 102 | for (int k = 0; k < a.length; k += 1) { 103 | size += a[k].length; 104 | } 105 | byte[] l = new byte[size]; 106 | int offset = 0; 107 | for (int k = 0; k < a.length; k += 1) { 108 | System.arraycopy(a[k], 0, l, offset, a[k].length); 109 | offset += a[k].length; 110 | } 111 | return l; 112 | } 113 | 114 | private byte[] byteArrayFromIntArray(int[] a) { 115 | byte[] l = new byte[a.length]; 116 | for (int k = 0; k < a.length; k += 1) { 117 | l[k] = (byte) (a[k] & 0xFF); 118 | } 119 | return l; 120 | } 121 | 122 | private int generateOneBuffer() { 123 | int[] buffer = {0}; 124 | GLES20.glGenBuffers(1, buffer, 0); 125 | return buffer[0]; 126 | } 127 | 128 | private int generateOneTexture() { 129 | int[] buffer = {0}; 130 | GLES20.glGenTextures(1, buffer, 0); 131 | return buffer[0]; 132 | } 133 | 134 | public void init() { 135 | shaderProgram = GLES20.glCreateProgram(); 136 | int vertShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); 137 | GLES20.glShaderSource(vertShader, vertexShaderProgram); 138 | GLES20.glCompileShader(vertShader); 139 | int fragShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); 140 | GLES20.glShaderSource(fragShader, fragmentShaderProgram); 141 | GLES20.glCompileShader(fragShader); 142 | GLES20.glAttachShader(shaderProgram, vertShader); 143 | GLES20.glAttachShader(shaderProgram, fragShader); 144 | GLES20.glLinkProgram(shaderProgram); 145 | GLES20.glUseProgram(shaderProgram); 146 | posCoord = GLES20.glGetAttribLocation(shaderProgram, "coord"); 147 | posTex = GLES20.glGetAttribLocation(shaderProgram, "texcoord"); 148 | posTrans = GLES20.glGetUniformLocation(shaderProgram, "trans"); 149 | posProj = GLES20.glGetUniformLocation(shaderProgram, "proj"); 150 | 151 | vboCoord = generateOneBuffer(); 152 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboCoord); 153 | float cube_vertices[][] = {{1.0f / 2, 1.0f / 2, 0.f}, {1.0f / 2, -1.0f / 2, 0.f}, {-1.0f / 2, -1.0f / 2, 0.f}, {-1.0f / 2, 1.0f / 2, 0.f}}; 154 | FloatBuffer cube_vertices_buffer = FloatBuffer.wrap(flatten(cube_vertices)); 155 | GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cube_vertices_buffer.limit() * 4, cube_vertices_buffer, GLES20.GL_DYNAMIC_DRAW); 156 | 157 | vboTex = generateOneBuffer(); 158 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboTex); 159 | int cube_vertex_colors[][] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}}; 160 | ByteBuffer cube_vertex_colors_buffer = ByteBuffer.wrap(byteArrayFromIntArray(flatten(cube_vertex_colors))); 161 | GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cube_vertex_colors_buffer.limit(), cube_vertex_colors_buffer, GLES20.GL_STATIC_DRAW); 162 | 163 | vboFaces = generateOneBuffer(); 164 | GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, vboFaces); 165 | short cube_faces[] = {3, 2, 1, 0}; 166 | ShortBuffer cube_faces_buffer = ShortBuffer.wrap(cube_faces); 167 | GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, cube_faces_buffer.limit() * 2, cube_faces_buffer, GLES20.GL_STATIC_DRAW); 168 | 169 | GLES20.glUniform1i(GLES20.glGetUniformLocation(shaderProgram, "texture"), 0); 170 | TextureHelper.texture = generateOneTexture(); 171 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, TextureHelper.texture); 172 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); 173 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 174 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); 175 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); 176 | } 177 | 178 | public void render(Matrix44F projectionMatrix, Matrix44F cameraview, Vec2F size) { 179 | float size0 = size.data[0]; 180 | float size1 = size.data[1]; 181 | 182 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboCoord); 183 | float height = size0 / 1000; 184 | float cube_vertices[][] = {{size0 / 2, size1 / 2, 0}, {size0 / 2, -size1 / 2, 0}, {-size0 / 2, -size1 / 2, 0}, {-size0 / 2, size1 / 2, 0}}; 185 | FloatBuffer cube_vertices_buffer = FloatBuffer.wrap(flatten(cube_vertices)); 186 | GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, cube_vertices_buffer.limit() * 4, cube_vertices_buffer, GLES20.GL_DYNAMIC_DRAW); 187 | 188 | GLES20.glEnable(GLES20.GL_BLEND); 189 | GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); 190 | GLES20.glEnable(GLES20.GL_DEPTH_TEST); 191 | GLES20.glUseProgram(shaderProgram); 192 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboCoord); 193 | GLES20.glEnableVertexAttribArray(posCoord); 194 | GLES20.glVertexAttribPointer(posCoord, 3, GLES20.GL_FLOAT, false, 0, 0); 195 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboTex); 196 | GLES20.glEnableVertexAttribArray(posTex); 197 | GLES20.glVertexAttribPointer(posTex, 2, GLES20.GL_UNSIGNED_BYTE, false, 0, 0); 198 | GLES20.glUniformMatrix4fv(posTrans, 1, false, cameraview.data, 0); 199 | GLES20.glUniformMatrix4fv(posProj, 1, false, projectionMatrix.data, 0); 200 | GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, vboFaces); 201 | 202 | GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, vboFaces); 203 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 204 | 205 | TextureHelper.updateTexture(); 206 | 207 | GLES20.glDrawElements(GLES20.GL_TRIANGLE_FAN, 4, GLES20.GL_UNSIGNED_SHORT, 0); 208 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/AR/Render/TextureHelper.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.AR.Render; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.opengl.GLES20; 7 | import android.opengl.GLUtils; 8 | import android.util.Log; 9 | 10 | import com.khoben.samples.studyar.ImageProcessing.ImageProcessing; 11 | 12 | 13 | public class TextureHelper { 14 | private static final String TAG = "TextureHelper"; 15 | 16 | public static int texture; 17 | private static Bitmap curBitmap; 18 | 19 | public static int loadTexture(final Context context, final int resourceId) { 20 | final int[] textureHandle = new int[1]; 21 | 22 | GLES20.glGenTextures(1, textureHandle, 0); 23 | 24 | if (textureHandle[0] == 0) { 25 | throw new RuntimeException("Error generating texture name."); 26 | } 27 | 28 | final BitmapFactory.Options options = new BitmapFactory.Options(); 29 | options.inScaled = false; // No pre-scaling 30 | 31 | // Read in the resource 32 | final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); 33 | 34 | // Bind to the texture in OpenGL 35 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 36 | 37 | // Set filtering 38 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 39 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 40 | 41 | // Load the bitmap into the bound texture. 42 | GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 43 | 44 | // Recycle the bitmap, since its data has been loaded into OpenGL. 45 | bitmap.recycle(); 46 | 47 | return textureHandle[0]; 48 | } 49 | 50 | public static int loadTexture(final Context context, final Bitmap bitmap) { 51 | final int[] textureHandle = new int[1]; 52 | 53 | GLES20.glGenTextures(1, textureHandle, 0); 54 | 55 | if (textureHandle[0] == 0) { 56 | throw new RuntimeException("Error generating texture name."); 57 | } 58 | 59 | final BitmapFactory.Options options = new BitmapFactory.Options(); 60 | options.inScaled = false; // No pre-scaling 61 | 62 | // Bind to the texture in OpenGL 63 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 64 | 65 | // Set filtering 66 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 67 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 68 | 69 | // Load the bitmap into the bound texture. 70 | GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 71 | 72 | // Recycle the bitmap, since its data has been loaded into OpenGL. 73 | bitmap.recycle(); 74 | 75 | return textureHandle[0]; 76 | } 77 | 78 | public static int loadTexture(final Context context, final String path) { 79 | final int[] textureHandle = new int[1]; 80 | 81 | GLES20.glGenTextures(1, textureHandle, 0); 82 | 83 | if (textureHandle[0] == 0) { 84 | throw new RuntimeException("Error generating texture name."); 85 | } 86 | 87 | final BitmapFactory.Options options = new BitmapFactory.Options(); 88 | options.inScaled = false; // No pre-scaling 89 | 90 | // Read in the resource 91 | final Bitmap bitmap = ImageProcessing.getBitmapFromAsset(context, path); 92 | 93 | // Bind to the texture in OpenGL 94 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 95 | 96 | // Set filtering 97 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 98 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 99 | 100 | // Load the bitmap into the bound texture. 101 | GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 102 | 103 | // Recycle the bitmap, since its data has been loaded into OpenGL. 104 | bitmap.recycle(); 105 | 106 | return textureHandle[0]; 107 | } 108 | 109 | public static void updateTexture() { 110 | Bitmap bitmap1; 111 | if (curBitmap == null) { 112 | bitmap1 = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); 113 | } else 114 | bitmap1 = Bitmap.createBitmap(curBitmap); 115 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture); 116 | GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap1, 0); 117 | bitmap1.recycle(); 118 | } 119 | 120 | public static void updateBitmap(final Bitmap bitmap){ 121 | curBitmap = bitmap; 122 | } 123 | } -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/DatabaseHelper/FirebaseHelper.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.DatabaseHelper; 2 | 3 | import com.google.firebase.database.DatabaseReference; 4 | import com.google.firebase.database.FirebaseDatabase; 5 | 6 | 7 | public class FirebaseHelper { 8 | static public DatabaseReference timetableReference; 9 | static public DatabaseReference titleReference; 10 | static public FirebaseDatabase firebaseDatabase; 11 | 12 | public static void init() { 13 | firebaseDatabase = FirebaseDatabase.getInstance(); 14 | firebaseDatabase.setPersistenceEnabled(true); 15 | 16 | titleReference = firebaseDatabase.getReference().child("title"); 17 | timetableReference = firebaseDatabase.getReference().child("timetable"); 18 | 19 | titleReference.keepSynced(true); 20 | timetableReference.keepSynced(true); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/ImageProcessing/ImagePool.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.ImageProcessing; 2 | 3 | import com.khoben.samples.studyar.Lesson; 4 | import com.khoben.samples.studyar.MainActivity; 5 | 6 | import java.util.Enumeration; 7 | import java.util.Iterator; 8 | 9 | 10 | public class ImagePool extends ObjectPool { 11 | 12 | public static final String TAG = "ImagePool"; 13 | 14 | private ImageProcessing imageProcessing; 15 | 16 | public ImagePool(MainActivity mainActivity) { 17 | super(); 18 | imageProcessing = new ImageProcessing(mainActivity); 19 | } 20 | 21 | 22 | @Override 23 | protected Lesson create(Lesson l) { 24 | l.setBitmap(imageProcessing.generateBitmap(l)); 25 | return l; 26 | } 27 | 28 | @Override 29 | public boolean validate(Lesson l) { 30 | for (Lesson l1 : unlocked.keySet()) { 31 | if (l1.getAud().equals(l.getAud())) { 32 | return true; 33 | } 34 | } 35 | return false; 36 | } 37 | 38 | public Lesson findExistingLesson(String aud) { 39 | for (Lesson l1 : unlocked.keySet()) { 40 | if (l1.getAud().equals(aud)) { 41 | return l1; 42 | } 43 | } 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/ImageProcessing/ImageProcessing.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.ImageProcessing; 2 | 3 | 4 | import android.content.Context; 5 | import android.content.res.AssetManager; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.Color; 9 | import android.graphics.Paint; 10 | import android.graphics.Rect; 11 | import android.graphics.Typeface; 12 | import android.util.Log; 13 | 14 | import com.khoben.samples.studyar.Lesson; 15 | import com.khoben.samples.studyar.MainActivity; 16 | import com.khoben.samples.studyar.Rubberstamp.RubberStamp; 17 | import com.khoben.samples.studyar.Rubberstamp.RubberStampConfig; 18 | import com.khoben.samples.studyar.Rubberstamp.RubberStampPosition; 19 | 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.util.HashMap; 24 | import java.util.LinkedHashMap; 25 | import java.util.Map; 26 | import java.util.concurrent.ConcurrentHashMap; 27 | import java.util.concurrent.ConcurrentSkipListMap; 28 | 29 | public class ImageProcessing { 30 | private static final String TAG = "ImageProcessing"; 31 | 32 | private Bitmap mainBitmap; 33 | private Bitmap teacherProfileBitmap; 34 | private MainActivity mainActivity; 35 | private RubberStampConfig config; 36 | private RubberStamp rubberStamp; 37 | 38 | private final static String boldFontPath = "fonts/Roboto-Bold.ttf"; 39 | private final static String regularFontPath = "fonts/Roboto-Regular.ttf"; 40 | private final static String italicFontPath = "fonts/Roboto-Italic.ttf"; 41 | private final static String lightItalicFontPath = "fonts/Roboto-LightItalic.ttf"; 42 | private final int fontSize = 100; 43 | 44 | private final int marginLeft = 30; 45 | private final int marginTop = 30; 46 | 47 | private final int scaleBitmapFactor = 4; 48 | 49 | public ImageProcessing() { 50 | } 51 | 52 | public ImageProcessing(MainActivity mainActivity) { 53 | this.mainActivity = mainActivity; 54 | rubberStamp = new RubberStamp(mainActivity); 55 | } 56 | 57 | public int getStringWidth(String s, String fontPath) { 58 | AssetManager assetManager = mainActivity.getAssets(); 59 | Paint paint = new Paint(); 60 | paint.setTextSize(fontSize); 61 | Typeface typeface = Typeface.createFromAsset(assetManager, fontPath); 62 | paint.setTypeface(typeface); 63 | paint.setColor(Color.BLACK); 64 | paint.setStyle(Paint.Style.FILL); 65 | Rect result = new Rect(); 66 | paint.getTextBounds(s, 0, s.length(), result); 67 | return result.width(); 68 | } 69 | 70 | public Bitmap generateBitmap(Lesson lesson) { 71 | 72 | if (lesson == null) { 73 | Log.w(TAG, "Lesson is NULL"); 74 | return null; 75 | } 76 | 77 | Log.i(TAG, lesson.toString()); 78 | 79 | Map lessonClassStringFields = new ConcurrentSkipListMap<>(); 80 | 81 | lessonClassStringFields.put(String.format("Аудитория №%s", lesson.getAud()), boldFontPath); 82 | lessonClassStringFields.put(lesson.getSubject(), regularFontPath); 83 | lessonClassStringFields.put(lesson.getFio(), regularFontPath); 84 | lessonClassStringFields.put(lesson.getDegree(), lightItalicFontPath); 85 | 86 | int maxWidth = 0; 87 | int cur; 88 | for (String string : lessonClassStringFields.keySet()) { 89 | cur = getStringWidth(string, lessonClassStringFields.get(string)); 90 | if (cur > maxWidth) 91 | maxWidth = cur; 92 | } 93 | 94 | teacherProfileBitmap = getBitmapFromAsset(mainActivity, String.format("teachers/%s.jpg", lesson.getFio().split(" ")[0])); 95 | 96 | if (teacherProfileBitmap == null) 97 | return null; 98 | 99 | teacherProfileBitmap = Bitmap.createScaledBitmap(teacherProfileBitmap, (teacherProfileBitmap.getWidth() * scaleBitmapFactor), 100 | (teacherProfileBitmap.getHeight() * scaleBitmapFactor), true); 101 | 102 | int amountLines = lessonClassStringFields.size(); 103 | 104 | mainBitmap = Bitmap.createBitmap(maxWidth + teacherProfileBitmap.getWidth() + marginLeft * 4, 105 | fontSize * amountLines + (amountLines + 2) * marginTop, Bitmap.Config.ARGB_8888); 106 | 107 | mainBitmap.eraseColor(Color.WHITE); 108 | 109 | config = new RubberStampConfig.RubberStampConfigBuilder() 110 | .base(mainBitmap) 111 | .rubberStamp(lessonClassStringFields) 112 | .rubberStamp(teacherProfileBitmap) 113 | .rubberStampPosition(RubberStampPosition.CUSTOM, teacherProfileBitmap.getWidth() + marginLeft, fontSize) 114 | .margin(marginLeft, marginTop) 115 | .textColor(Color.BLACK) 116 | .textSize(fontSize) 117 | .textFont(regularFontPath) 118 | .build(); 119 | 120 | mainBitmap = rubberStamp.addStamp(config); 121 | 122 | return mainBitmap; 123 | } 124 | 125 | 126 | public static Bitmap getBitmapFromAsset(Context context, String filePath) { 127 | AssetManager assetManager = context.getAssets(); 128 | 129 | InputStream istr; 130 | Bitmap bitmap = null; 131 | try { 132 | istr = assetManager.open(filePath); 133 | bitmap = BitmapFactory.decodeStream(istr); 134 | } catch (IOException e) { 135 | Log.e(TAG, "Не удалось загрузить изображение"); 136 | } 137 | 138 | return bitmap; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/ImageProcessing/ObjectPool.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.ImageProcessing; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | public abstract class ObjectPool { 7 | protected long expirationTime; 8 | 9 | protected Map unlocked; 10 | 11 | public ObjectPool() { 12 | expirationTime = 30000; // 30 sec 13 | unlocked = new ConcurrentHashMap<>(); 14 | } 15 | 16 | protected abstract T create(T l); 17 | 18 | public abstract boolean validate(T l); 19 | 20 | public synchronized T checkOut(T l) { 21 | long now = System.currentTimeMillis(); 22 | T t; 23 | if (unlocked.size() > 0) { 24 | for (T t1 : unlocked.keySet()) { 25 | t = t1; 26 | if ((now - unlocked.get(t)) > expirationTime) { 27 | unlocked.remove(t); 28 | t = null; 29 | } else { 30 | if (validate(l)) { 31 | return t; 32 | } else { 33 | t = null; 34 | } 35 | } 36 | } 37 | } 38 | 39 | t = create(l); 40 | unlocked.put(t, now); 41 | return t; 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/Lesson.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar; 2 | 3 | 4 | import android.graphics.Bitmap; 5 | 6 | import com.google.firebase.database.Exclude; 7 | 8 | public class Lesson { 9 | 10 | private String aud; 11 | private String subject; 12 | private String fio; 13 | private String degree; 14 | 15 | 16 | @Exclude 17 | private Bitmap bitmap; 18 | 19 | public Lesson() { 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "Lesson{" + 25 | "aud='" + aud + '\'' + 26 | ", subject='" + subject + '\'' + 27 | ", fio='" + fio + '\'' + 28 | ", degree='" + degree + '\'' + 29 | '}'; 30 | } 31 | 32 | public Lesson(String aud, String fio, String subject, String degree) { 33 | this.aud = aud; 34 | this.fio = fio; 35 | this.subject = subject; 36 | this.degree = degree; 37 | } 38 | 39 | public String getAud() { 40 | return aud; 41 | } 42 | 43 | public void setAud(String aud) { 44 | this.aud = aud; 45 | } 46 | 47 | public String getSubject() { 48 | return subject; 49 | } 50 | 51 | public void setSubject(String subject) { 52 | this.subject = subject; 53 | } 54 | 55 | public String getFio() { 56 | return fio; 57 | } 58 | 59 | public void setFio(String fio) { 60 | this.fio = fio; 61 | } 62 | 63 | public String getDegree() { 64 | return degree; 65 | } 66 | 67 | public void setDegree(String degree) { 68 | this.degree = degree; 69 | } 70 | 71 | public Bitmap getBitmap() { 72 | return bitmap; 73 | } 74 | 75 | public void setBitmap(Bitmap bitmap) { 76 | this.bitmap = bitmap; 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/MainActivity.java: -------------------------------------------------------------------------------- 1 | //================================================================================================================================ 2 | // 3 | // Copyright (c) 2015-2017 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved. 4 | // EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China 5 | // and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd. 6 | // 7 | //================================================================================================================================ 8 | 9 | package com.khoben.samples.studyar; 10 | 11 | import android.Manifest; 12 | import android.annotation.TargetApi; 13 | import android.content.pm.PackageManager; 14 | import android.opengl.GLSurfaceView; 15 | import android.os.Build; 16 | import android.os.Bundle; 17 | import android.support.annotation.NonNull; 18 | import android.support.v7.app.AppCompatActivity; 19 | import android.util.Log; 20 | import android.view.Menu; 21 | import android.view.MenuItem; 22 | import android.view.ViewGroup; 23 | import android.view.WindowManager; 24 | 25 | import com.google.firebase.database.DataSnapshot; 26 | import com.google.firebase.database.DatabaseError; 27 | import com.google.firebase.database.ValueEventListener; 28 | import com.khoben.samples.studyar.AR.AR; 29 | 30 | import java.util.HashMap; 31 | 32 | import com.khoben.samples.studyar.AR.MyAR; 33 | import com.khoben.samples.studyar.DatabaseHelper.FirebaseHelper; 34 | 35 | 36 | public class MainActivity extends AppCompatActivity { 37 | private final String TAG = "MainActivity"; 38 | private GLSurfaceView glView; 39 | private AR ar; 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_main); 45 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 46 | 47 | FirebaseHelper.init(); 48 | 49 | ar = MyAR.getInstance(this); 50 | ar.initAR(); 51 | 52 | glView = ar.getGLView(); 53 | 54 | FirebaseHelper.titleReference.addValueEventListener(new ValueEventListener() { 55 | @Override 56 | public void onDataChange(DataSnapshot dataSnapshot) { 57 | String value = dataSnapshot.getValue(String.class); 58 | try { 59 | getSupportActionBar().setTitle(value); 60 | } 61 | catch (NullPointerException e){ 62 | Log.e(TAG,e.getMessage()); 63 | } 64 | } 65 | 66 | @Override 67 | public void onCancelled(DatabaseError databaseError) { 68 | 69 | } 70 | }); 71 | 72 | requestCameraPermission(new PermissionCallback() { 73 | @Override 74 | public void onSuccess() { 75 | ((ViewGroup) findViewById(R.id.preview)).addView(glView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 76 | } 77 | 78 | @Override 79 | public void onFailure() { 80 | } 81 | }); 82 | } 83 | 84 | private interface PermissionCallback { 85 | void onSuccess(); 86 | 87 | void onFailure(); 88 | } 89 | 90 | private HashMap permissionCallbacks = new HashMap(); 91 | private int permissionRequestCodeSerial = 0; 92 | 93 | @TargetApi(23) 94 | private void requestCameraPermission(PermissionCallback callback) { 95 | if (Build.VERSION.SDK_INT >= 23) { 96 | if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { 97 | int requestCode = permissionRequestCodeSerial; 98 | permissionRequestCodeSerial += 1; 99 | permissionCallbacks.put(requestCode, callback); 100 | requestPermissions(new String[]{Manifest.permission.CAMERA}, requestCode); 101 | } else { 102 | callback.onSuccess(); 103 | } 104 | } else { 105 | callback.onSuccess(); 106 | } 107 | } 108 | 109 | @Override 110 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 111 | if (permissionCallbacks.containsKey(requestCode)) { 112 | PermissionCallback callback = permissionCallbacks.get(requestCode); 113 | permissionCallbacks.remove(requestCode); 114 | boolean executed = false; 115 | for (int result : grantResults) { 116 | if (result != PackageManager.PERMISSION_GRANTED) { 117 | executed = true; 118 | callback.onFailure(); 119 | } 120 | } 121 | if (!executed) { 122 | callback.onSuccess(); 123 | } 124 | } 125 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 126 | } 127 | 128 | @Override 129 | protected void onResume() { 130 | super.onResume(); 131 | if (glView != null) { 132 | glView.onResume(); 133 | } 134 | } 135 | 136 | @Override 137 | protected void onPause() { 138 | if (glView != null) { 139 | glView.onPause(); 140 | } 141 | super.onPause(); 142 | } 143 | 144 | @Override 145 | public boolean onCreateOptionsMenu(Menu menu) { 146 | getMenuInflater().inflate(R.menu.menu_main, menu); 147 | return true; 148 | } 149 | 150 | @Override 151 | public boolean onOptionsItemSelected(MenuItem item) { 152 | int id = item.getItemId(); 153 | 154 | switch (id) { 155 | case R.id.flashlight: 156 | ar.toogleFlashlightState(); 157 | 158 | if (ar.getFlashlightState()) { 159 | item.setIcon(R.drawable.flashlight_off); 160 | } else 161 | item.setIcon(R.drawable.flashlight); 162 | return true; 163 | } 164 | 165 | return super.onOptionsItemSelected(item); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/MyIterator/MyContainer.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.MyIterator; 2 | 3 | 4 | import java.util.List; 5 | 6 | public interface MyContainer { 7 | MyIterator getIterator(); 8 | void add(E obj); 9 | void remove(E obj); 10 | void set(List objectList); 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/MyIterator/MyIterator.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.MyIterator; 2 | 3 | 4 | public interface MyIterator { 5 | boolean hasNext(); 6 | E next(); 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/MyIterator/TargetContainer.java: -------------------------------------------------------------------------------- 1 | package com.khoben.samples.studyar.MyIterator; 2 | 3 | 4 | import java.util.List; 5 | 6 | public class TargetContainer implements MyContainer { 7 | private List objectList; 8 | 9 | public TargetContainer(List objectList){ 10 | set(objectList); 11 | } 12 | 13 | @Override 14 | public MyIterator getIterator() { 15 | return new TargetIterator(); 16 | } 17 | 18 | @Override 19 | public void add(E obj) { 20 | objectList.add(obj); 21 | } 22 | 23 | @Override 24 | public void remove(E obj) { 25 | objectList.remove(obj); 26 | } 27 | 28 | @Override 29 | public void set(List objectList) { 30 | this.objectList = objectList; 31 | } 32 | 33 | 34 | private class TargetIterator implements MyIterator { 35 | 36 | private int index; 37 | 38 | @Override 39 | public boolean hasNext() { 40 | 41 | if(index < objectList.size()){ 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | @Override 48 | public E next() { 49 | 50 | if(this.hasNext()){ 51 | return objectList.get(index++); 52 | } 53 | return null; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/Rubberstamp/PositionCalculator.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Vinay Gaba 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package com.khoben.samples.studyar.Rubberstamp; 17 | 18 | import android.util.Pair; 19 | 20 | public class PositionCalculator { 21 | 22 | /** 23 | * Utility method to calculate the coordinates of the rubberstamp based on the params passed to 24 | * it. 25 | * @param location The RubberStampPosition which denotes the position of the watermark 26 | * @param bitmapWidth The width of the bitmap where the rubberstamp will be drawn 27 | * @param bitmapHeight The height of the bitmap where the rubberstamp will be drawn 28 | * @param rubberstampWidth The width of the rubberstamp 29 | * @param rubberstampHeight The height of the rubberstamp 30 | * @return Returns a Pair object which has the x-coordinate and the y-coordinate 31 | */ 32 | public static Pair getCoordinates(RubberStampPosition location, 33 | int bitmapWidth, int bitmapHeight, 34 | int rubberstampWidth, int rubberstampHeight) { 35 | switch(location){ 36 | case TOP_LEFT: 37 | return new Pair<>(0, rubberstampHeight); 38 | 39 | case TOP_CENTER: 40 | return new Pair<>((bitmapWidth / 2) - (rubberstampWidth / 2), 41 | rubberstampHeight); 42 | case TOP_RIGHT: 43 | return new Pair<>(bitmapWidth - rubberstampWidth, rubberstampHeight); 44 | 45 | case CENTER_LEFT: 46 | return new Pair<>(0, (bitmapHeight / 2) + (rubberstampHeight / 2)); 47 | 48 | case CENTER: 49 | return new Pair<>((bitmapWidth / 2) - (rubberstampWidth / 2), 50 | (bitmapHeight / 2) + (rubberstampHeight / 2)); 51 | case CENTER_RIGHT: 52 | return new Pair<>(bitmapWidth - rubberstampWidth, 53 | (bitmapHeight / 2) + (rubberstampHeight / 2)); 54 | 55 | case BOTTOM_LEFT: 56 | return new Pair<>(0, bitmapHeight); 57 | 58 | case BOTTOM_CENTER: 59 | return new Pair<>((bitmapWidth / 2) - (rubberstampWidth / 2), 60 | bitmapHeight); 61 | case BOTTOM_RIGHT: 62 | return new Pair<>(bitmapWidth - rubberstampWidth, bitmapHeight); 63 | 64 | default: 65 | return new Pair<>((bitmapWidth / 2) - (rubberstampWidth / 2), 66 | (bitmapHeight / 2) + (rubberstampHeight / 2)); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/Rubberstamp/RubberStamp.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Vinay Gaba 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.khoben.samples.studyar.Rubberstamp; 18 | 19 | import android.content.Context; 20 | import android.graphics.Bitmap; 21 | import android.graphics.BitmapFactory; 22 | import android.graphics.BitmapShader; 23 | import android.graphics.Canvas; 24 | import android.graphics.Paint; 25 | import android.graphics.Rect; 26 | import android.graphics.Shader; 27 | import android.graphics.Typeface; 28 | import android.support.annotation.DrawableRes; 29 | import android.support.annotation.NonNull; 30 | import android.support.annotation.Nullable; 31 | import android.text.TextUtils; 32 | import android.util.Pair; 33 | 34 | import java.util.HashMap; 35 | import java.util.Map; 36 | 37 | import static com.khoben.samples.studyar.Rubberstamp.RubberStampPosition.CUSTOM; 38 | import static com.khoben.samples.studyar.Rubberstamp.RubberStampPosition.TILE; 39 | 40 | 41 | public class RubberStamp { 42 | 43 | private Context mContext; 44 | private static final int BACKGROUND_MARGIN = 10; 45 | 46 | public RubberStamp(@NonNull Context context) { 47 | mContext = context; 48 | } 49 | 50 | public Bitmap addStamp(@NonNull RubberStampConfig config) { 51 | if (config == null) { 52 | throw new IllegalArgumentException("The config passed to this method should never" + 53 | "be null"); 54 | } 55 | Bitmap baseBitmap = getBaseBitmap(config); 56 | if (baseBitmap == null) { 57 | return baseBitmap; 58 | } 59 | 60 | int baseBitmapWidth = baseBitmap.getWidth(); 61 | int baseBitmapHeight = baseBitmap.getHeight(); 62 | 63 | Bitmap result = Bitmap.createBitmap(baseBitmapWidth, baseBitmapHeight, baseBitmap.getConfig()); 64 | Canvas canvas = new Canvas(result); 65 | canvas.drawBitmap(baseBitmap, 0, 0, null); 66 | 67 | // Either one of the methods(text/bitmap) can be used to add a rubberstamp 68 | if (config.getRubberStampString() != null) { 69 | addTextToBitmap(config, canvas, baseBitmapWidth, baseBitmapHeight); 70 | } 71 | if (config.getRubberStampBitmap() != null) { 72 | addBitmapToBitmap(config.getRubberStampBitmap(), config, canvas, 73 | baseBitmapWidth, baseBitmapHeight); 74 | } 75 | return result; 76 | } 77 | 78 | @Nullable 79 | private Bitmap getBaseBitmap(@NonNull RubberStampConfig config) { 80 | Bitmap baseBitmap = config.getBaseBitmap(); 81 | @DrawableRes int drawable = config.getBaseDrawable(); 82 | 83 | if (baseBitmap == null) { 84 | baseBitmap = BitmapFactory.decodeResource(mContext.getResources(), drawable); 85 | if (baseBitmap == null) return null; 86 | } 87 | return baseBitmap; 88 | } 89 | 90 | /** 91 | * Method to add text RubberStamp to a canvas based on the provided configuration 92 | * 93 | * @param config The RubberStampConfig that specifies how the RubberStamp should look 94 | * @param canvas The canvas on top of which the RubberStamp needs to be drawn 95 | * @param baseBitmapWidth The width of the base bitmap 96 | * @param baseBitmapHeight The height of the base bitmap 97 | */ 98 | private void addTextToBitmap(@NonNull RubberStampConfig config, 99 | @NonNull Canvas canvas, 100 | int baseBitmapWidth, 101 | int baseBitmapHeight) { 102 | Rect bounds = new Rect(); 103 | 104 | Paint paint = new Paint(); 105 | paint.setAntiAlias(true); 106 | paint.setUnderlineText(false); 107 | 108 | paint.setTextSize(config.getTextSize()); 109 | 110 | Shader shader = config.getTextShader(); 111 | // Add shader if its present in the config. 112 | if (shader != null) { 113 | paint.setShader(shader); 114 | } 115 | 116 | if (config.getTextShadowXOffset() != 0 || config.getTextShadowYOffset() != 0 117 | || config.getTextShadowBlurRadius() != 0) { 118 | // If any shadow property is present, set a shadow layer. 119 | paint.setShadowLayer(config.getTextShadowBlurRadius(), 120 | config.getTextShadowXOffset(), 121 | config.getTextShadowYOffset(), 122 | config.getTextShadowColor()); 123 | } 124 | 125 | Map rubberStampString = config.getRubberStampString(); 126 | 127 | int startH = 0; 128 | 129 | for (String str : config.getRubberStampString().keySet()) { 130 | 131 | Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), config.getRubberStampString().get(str)); 132 | paint.setTypeface(typeface); 133 | 134 | paint.getTextBounds(str, 0, str.length(), bounds); 135 | 136 | int rubberStampWidth = bounds.width(); 137 | float rubberStampMeasuredWidth = paint.measureText(str); 138 | int rubberStampHeight = bounds.height(); 139 | 140 | int positionX = config.getPositionX(); 141 | int positionY = config.getPositionY() + startH; 142 | 143 | startH += config.getTextSize(); 144 | 145 | if (config.getRubberStampPosition() != CUSTOM) { 146 | // If the specified RubberStampPosition is not CUSTOM, use calculates its x & y 147 | // co-ordinates. 148 | Pair pair = PositionCalculator 149 | .getCoordinates(config.getRubberStampPosition(), 150 | baseBitmapWidth, baseBitmapHeight, 151 | rubberStampWidth, rubberStampHeight); 152 | positionX = pair.first; 153 | positionY = pair.second; 154 | } 155 | 156 | // Add the margin to this position if it was passed to the config. 157 | positionX += config.getXMargin(); 158 | positionY += config.getYMargin(); 159 | 160 | float rotation = config.getRotation(); 161 | // Add rotation if its present in the config. 162 | if (rotation != 0.0f) { 163 | canvas.rotate(rotation, positionX + bounds.exactCenterX(), 164 | positionY - bounds.exactCenterY()); 165 | } 166 | 167 | // Add the specified text color if its present in the config or it will use the default value. 168 | paint.setColor(config.getTextColor()); 169 | 170 | int alpha = config.getAplha(); 171 | // Add alpha to the rubberstamp if its within range or it uses the default value. 172 | if (alpha >= 0 && alpha <= 255) { 173 | paint.setAlpha(alpha); 174 | } 175 | 176 | if (config.getRubberStampPosition() != TILE) { 177 | // The textBackgroundColor is only used if the specified RubberStampPosition is not TILE 178 | // This is because the background is actually a rectangle whose bounds are calcualted 179 | // below. In the case of TILE, we make use of a bitmap shader and there was no easy way 180 | // to draw the background rectangle for each tiled rubberstamp. 181 | int backgroundColor = config.getTextBackgroundColor(); 182 | if (backgroundColor != 0) { 183 | Paint backgroundPaint = new Paint(); 184 | backgroundPaint.setColor(backgroundColor); 185 | canvas.drawRect(positionX - BACKGROUND_MARGIN, 186 | positionY - bounds.height() - paint.getFontMetrics().descent - BACKGROUND_MARGIN, 187 | (positionX + rubberStampMeasuredWidth + config.getTextShadowXOffset() + BACKGROUND_MARGIN), 188 | positionY + config.getTextShadowYOffset() + paint.getFontMetrics().descent + BACKGROUND_MARGIN, 189 | backgroundPaint); 190 | } 191 | canvas.drawText(str, positionX, positionY, paint); 192 | } else { 193 | // If the specified RubberStampPosition is TILE, it tiles the rubberstamp across 194 | // the bitmap. In order to generate a tiled bitamp, it uses a bitmap shader. 195 | Bitmap textImage = Bitmap.createBitmap((int) rubberStampMeasuredWidth, 196 | rubberStampHeight, 197 | Bitmap.Config.ARGB_8888); 198 | Canvas textCanvas = new Canvas(textImage); 199 | textCanvas.drawText(str, 0, rubberStampHeight, paint); 200 | paint.setShader(new BitmapShader(textImage, 201 | Shader.TileMode.REPEAT, 202 | Shader.TileMode.REPEAT)); 203 | Rect bitmapShaderRect = canvas.getClipBounds(); 204 | canvas.drawRect(bitmapShaderRect, paint); 205 | } 206 | 207 | } 208 | } 209 | 210 | /** 211 | * Method to add a bitmap RubberStamp to a canvas based on the provided configuration 212 | * 213 | * @param rubberStampBitmap The bitmap which will be used as the RubberStamp 214 | * @param config The RubberStampConfig that specifies how the RubberStamp should look 215 | * @param canvas The canvas on top of which the RubberStamp needs to be drawn 216 | * @param baseBitmapWidth The width of the base bitmap 217 | * @param baseBitmapHeight The height of the base bitmap 218 | */ 219 | private void addBitmapToBitmap(@NonNull Bitmap rubberStampBitmap, 220 | @NonNull RubberStampConfig config, 221 | @NonNull Canvas canvas, 222 | int baseBitmapWidth, 223 | int baseBitmapHeight) { 224 | Paint paint = new Paint(); 225 | paint.setAntiAlias(true); 226 | paint.setUnderlineText(false); 227 | 228 | int alpha = config.getAplha(); 229 | // Add alpha to the rubberstamp if its within range or it uses the default value. 230 | if (alpha >= 0 && alpha <= 255) { 231 | paint.setAlpha(alpha); 232 | } 233 | 234 | // int positionX = config.getPositionX(); 235 | // int positionY = config.getPositionY(); 236 | 237 | int positionX = 0; 238 | int positionY = 0; 239 | 240 | RubberStampPosition rubberStampPosition = config.getRubberStampPosition(); 241 | if (rubberStampPosition != CUSTOM) { 242 | // If the specified RubberStampPosition is not CUSTOM, use calculates its x & y 243 | // co-ordinates. 244 | Pair pair = 245 | PositionCalculator.getCoordinates(rubberStampPosition, 246 | baseBitmapWidth, baseBitmapHeight, 247 | rubberStampBitmap.getWidth(), rubberStampBitmap.getHeight()); 248 | positionX = pair.first; 249 | positionY = pair.second - rubberStampBitmap.getHeight(); 250 | } 251 | 252 | // Add the margin to this position if it was passed to the config. 253 | positionX += config.getXMargin(); 254 | positionY += config.getYMargin(); 255 | 256 | float rotation = config.getRotation(); 257 | if (rotation != 0.0f) { 258 | // Add rotation if its present in the config. 259 | canvas.rotate(rotation, positionX + (rubberStampBitmap.getWidth() / 2), 260 | positionY + (rubberStampBitmap.getHeight() / 2)); 261 | } 262 | 263 | if (rubberStampPosition != TILE) { 264 | canvas.drawBitmap(rubberStampBitmap, positionX, positionY, paint); 265 | } else { 266 | // If the specified RubberStampPosition is TILE, it tiles the rubberstamp across 267 | // the bitmap. In order to generate a tiled bitamp, it uses a bitmap shader. 268 | paint.setShader(new BitmapShader(rubberStampBitmap, 269 | Shader.TileMode.REPEAT, 270 | Shader.TileMode.REPEAT)); 271 | Rect bitmapShaderRect = canvas.getClipBounds(); 272 | canvas.drawRect(bitmapShaderRect, paint); 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/Rubberstamp/RubberStampConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Vinay Gaba 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package com.khoben.samples.studyar.Rubberstamp; 17 | 18 | import android.graphics.Bitmap; 19 | import android.graphics.Color; 20 | import android.graphics.Shader; 21 | import android.support.annotation.ColorInt; 22 | import android.support.annotation.DrawableRes; 23 | 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | import static com.khoben.samples.studyar.Rubberstamp.RubberStampPosition.CENTER; 28 | 29 | 30 | public class RubberStampConfig { 31 | 32 | private Bitmap mBaseBitmap; 33 | @DrawableRes private int mBaseDrawable; 34 | private int mTextSize; 35 | @ColorInt private int mTextColor; 36 | @ColorInt private int mTextBackgroundColor; 37 | private String mTypeFacePath; 38 | private RubberStampPosition mRubberStampPosition; 39 | private Map mRubberStampString; 40 | private Bitmap mRubberStampBitmap; 41 | private int mAplha; 42 | private Shader mTextShader; 43 | private float mRotation; 44 | private int mPositionX, mPositionY; 45 | private float mTextShadowBlurRadius, mTextShadowXOffset, mTextShadowYOffset; 46 | private int mTextShadowColor; 47 | private int mXMargin, mYMargin; 48 | 49 | private RubberStampConfig(RubberStampConfigBuilder builder) { 50 | this.mBaseBitmap = builder.mBaseBitmap; 51 | this.mBaseDrawable = builder.mBaseDrawable; 52 | this.mTextSize = builder.mTextSize; 53 | this.mTextColor = builder.mTextColor; 54 | this.mTextBackgroundColor = builder.mTextBackgroundColor; 55 | this.mTypeFacePath = builder.mTypeFacePath; 56 | this.mRubberStampPosition = builder.mRubberStampPosition; 57 | this.mRubberStampString = builder.mRubberStampString; 58 | this.mRubberStampBitmap = builder.mRubberStampBitmap; 59 | this.mAplha = builder.mAlpha; 60 | this.mTextShader = builder.mTextShader; 61 | this.mRotation = builder.mRotation; 62 | this.mPositionX = builder.mPositionX; 63 | this.mPositionY = builder.mPositionY; 64 | this.mTextShadowColor = builder.mTextShadowColor; 65 | this.mTextShadowXOffset = builder.mTextShadowXOffset; 66 | this.mTextShadowYOffset = builder.mTextShadowYOffset; 67 | this.mTextShadowBlurRadius = builder.mTextShadowBlurRadius; 68 | this.mXMargin = builder.mXMargin; 69 | this.mYMargin = builder.mYMargin; 70 | } 71 | 72 | public Bitmap getBaseBitmap() { 73 | return mBaseBitmap; 74 | } 75 | 76 | protected int getBaseDrawable() { 77 | return mBaseDrawable; 78 | } 79 | 80 | public int getTextSize() { 81 | return mTextSize; 82 | } 83 | 84 | public int getTextColor() { 85 | return mTextColor; 86 | } 87 | 88 | public int getTextBackgroundColor() { 89 | return mTextBackgroundColor; 90 | } 91 | 92 | public String getTypeFacePath() { 93 | return mTypeFacePath; 94 | } 95 | 96 | public RubberStampPosition getRubberStampPosition() { 97 | return mRubberStampPosition; 98 | } 99 | 100 | public Map getRubberStampString() { 101 | return mRubberStampString; 102 | } 103 | 104 | protected Bitmap getRubberStampBitmap() { 105 | return mRubberStampBitmap; 106 | } 107 | 108 | public int getAplha() { 109 | return mAplha; 110 | } 111 | 112 | public Shader getTextShader() { 113 | return mTextShader; 114 | } 115 | 116 | public float getRotation() { 117 | return mRotation; 118 | } 119 | 120 | public int getPositionX() { 121 | return mPositionX; 122 | } 123 | 124 | public int getPositionY() { 125 | return mPositionY; 126 | } 127 | 128 | public float getTextShadowBlurRadius() { 129 | return mTextShadowBlurRadius; 130 | } 131 | 132 | public float getTextShadowXOffset() { 133 | return mTextShadowXOffset; 134 | } 135 | 136 | public float getTextShadowYOffset() { 137 | return mTextShadowYOffset; 138 | } 139 | 140 | public int getTextShadowColor() { 141 | return mTextShadowColor; 142 | } 143 | 144 | public int getXMargin() { 145 | return mXMargin; 146 | } 147 | 148 | public int getYMargin() { 149 | return mYMargin; 150 | } 151 | 152 | public static class RubberStampConfigBuilder { 153 | 154 | private Bitmap mBaseBitmap; 155 | @DrawableRes private int mBaseDrawable; 156 | private int mTextSize = 40; 157 | @ColorInt private int mTextColor = Color.BLACK; 158 | @ColorInt private int mTextBackgroundColor; 159 | private String mTypeFacePath; 160 | private RubberStampPosition mRubberStampPosition = CENTER; 161 | private Map mRubberStampString; 162 | private Bitmap mRubberStampBitmap; 163 | private int mAlpha = 255; 164 | private Shader mTextShader; 165 | private float mRotation; 166 | private int mPositionX, mPositionY; 167 | private float mTextShadowBlurRadius, mTextShadowXOffset, mTextShadowYOffset; 168 | @ColorInt private int mTextShadowColor = Color.WHITE; 169 | private int mXMargin, mYMargin; 170 | 171 | public RubberStampConfigBuilder base(final Bitmap bitmap) { 172 | this.mBaseBitmap = bitmap; 173 | return this; 174 | } 175 | 176 | public RubberStampConfigBuilder base(@DrawableRes int drawable) { 177 | this.mBaseDrawable = drawable; 178 | return this; 179 | } 180 | 181 | public RubberStampConfigBuilder textSize(final int size) { 182 | this.mTextSize = size; 183 | return this; 184 | } 185 | 186 | public RubberStampConfigBuilder textColor(final int color) { 187 | this.mTextColor = color; 188 | return this; 189 | } 190 | 191 | public RubberStampConfigBuilder textBackgroundColor(final int color) { 192 | this.mTextBackgroundColor = color; 193 | return this; 194 | } 195 | 196 | public RubberStampConfigBuilder textFont(final String typeFacePath) { 197 | this.mTypeFacePath = typeFacePath; 198 | return this; 199 | } 200 | 201 | public RubberStampConfigBuilder rubberStampPosition(final RubberStampPosition position, 202 | final int positionX, 203 | final int positionY) { 204 | if (position != RubberStampPosition.CUSTOM) { 205 | throw new IllegalArgumentException("This constructor can only be used when the " + 206 | "rubberStampPosition is RubberStamp.CUSTOM"); 207 | } 208 | this.mRubberStampPosition = position; 209 | this.mPositionX = positionX; 210 | this.mPositionY = positionY; 211 | return this; 212 | } 213 | 214 | public RubberStampConfigBuilder rubberStampPosition(final RubberStampPosition position) { 215 | this.mRubberStampPosition = position; 216 | return this; 217 | } 218 | 219 | public RubberStampConfigBuilder rubberStamp(final Map rubberStampString) { 220 | this.mRubberStampString = rubberStampString; 221 | return this; 222 | } 223 | 224 | public RubberStampConfigBuilder rubberStamp(final Bitmap rubberStampBitmap) { 225 | this.mRubberStampBitmap = rubberStampBitmap; 226 | return this; 227 | } 228 | 229 | public RubberStampConfigBuilder alpha(final int alpha) { 230 | this.mAlpha = alpha; 231 | return this; 232 | } 233 | 234 | public RubberStampConfigBuilder textShader(final Shader shader) { 235 | this.mTextShader = shader; 236 | return this; 237 | } 238 | 239 | public RubberStampConfigBuilder rotation(final float rotation) { 240 | this.mRotation = rotation; 241 | return this; 242 | } 243 | 244 | public RubberStampConfigBuilder textShadow(final float blurRadius, final float shadowXOffset, 245 | final float shadowYOffset,@ColorInt final int shadowColor) { 246 | this.mTextShadowBlurRadius = blurRadius; 247 | this.mTextShadowXOffset = shadowXOffset; 248 | this.mTextShadowYOffset = shadowYOffset; 249 | this.mTextShadowColor = shadowColor; 250 | return this; 251 | } 252 | 253 | public RubberStampConfigBuilder margin(final int xMargin, final int yMargin) { 254 | this.mXMargin = xMargin; 255 | this.mYMargin = yMargin; 256 | return this; 257 | } 258 | 259 | public RubberStampConfig build() { 260 | return new RubberStampConfig(this); 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /app/src/main/java/com/khoben/samples/studyar/Rubberstamp/RubberStampPosition.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2017 Vinay Gaba 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package com.khoben.samples.studyar.Rubberstamp; 17 | 18 | /** 19 | * Enums to represent the position configurations of the rubberstamp 20 | */ 21 | public enum RubberStampPosition { 22 | TOP_LEFT, TOP_RIGHT, TOP_CENTER, CENTER_LEFT, CENTER_RIGHT, CENTER, BOTTOM_LEFT, BOTTOM_RIGHT, 23 | BOTTOM_CENTER, CUSTOM, TILE 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libEasyAR.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/jniLibs/armeabi-v7a/libEasyAR.so -------------------------------------------------------------------------------- /app/src/main/res/drawable/flashlight.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/flashlight_off.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/transition.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | studyAR 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.0.1' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | classpath 'com.google.gms:google-services:3.1.0' 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | jcenter() 20 | google() 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Mon Dec 05 16:06:30 CST 2016 16 | org.gradle.jvmargs=-Xmx1536m 17 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Jan 11 16:12:42 GMT+07:00 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /uml/desktop.ini: -------------------------------------------------------------------------------- 1 | [LocalizedFileNames] 2 | uml.vpp=@uml,0 3 | -------------------------------------------------------------------------------- /uml/uml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/uml/uml.png -------------------------------------------------------------------------------- /uml/uml.vpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoben/studyAR/7bbea7224e9c44e0ebda977844d772431b333e4d/uml/uml.vpp --------------------------------------------------------------------------------