From e0a2bbdbaba3a0729a5327907110a5770fddf102 Mon Sep 17 00:00:00 2001 From: Robert Chrzanowski Date: Tue, 6 Feb 2024 12:45:51 -0500 Subject: [PATCH] Updated dependencies and moved dependencies to libs.versions.toml --- .idea/.gitignore | 3 + app/build.gradle | 148 -------------- app/build.gradle.kts | 115 +++++++++++ app/src/main/assets/materials/depth.filamat | Bin 17797 -> 23588 bytes app/src/main/assets/materials/flat.filamat | Bin 13861 -> 22070 bytes app/src/main/assets/materials/shadow.filamat | Bin 37600 -> 160840 bytes .../main/assets/materials/textured.filamat | Bin 12607 -> 25720 bytes app/src/main/java/com/example/app/Matrix.kt | 104 ++++++++-- app/src/main/java/com/example/app/OpenGL.kt | 8 +- .../com/example/app/aractivity/ArActivity.kt | 46 ++++- .../java/com/example/app/arcore/ArCore.kt | 86 +++++--- .../java/com/example/app/filament/Filament.kt | 13 +- .../app/gesture/BaseGestureRecognizer.kt | 2 +- .../com/example/app/gesture/DragGesture.kt | 6 +- .../app/gesture/GesturePointersUtility.kt | 1 - .../com/example/app/gesture/PinchGesture.kt | 17 +- .../com/example/app/gesture/TwistGesture.kt | 10 +- .../com/example/app/renderer/FrameCallback.kt | 13 +- .../com/example/app/renderer/LightRenderer.kt | 13 +- .../com/example/app/renderer/ModelRenderer.kt | 29 ++- .../com/example/app/renderer/PlaneRenderer.kt | 49 +++-- build.gradle | 31 --- build.gradle.kts | 62 ++++++ gradle/libs.versions.toml | 186 ++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 2 - settings.gradle.kts | 21 ++ 27 files changed, 692 insertions(+), 275 deletions(-) create mode 100644 .idea/.gitignore delete mode 100644 app/build.gradle create mode 100644 app/build.gradle.kts delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 gradle/libs.versions.toml delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 6568da3..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,148 +0,0 @@ -apply plugin: 'com.android.application' - -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-parcelize' -apply plugin: 'kotlin-kapt' - -apply plugin: 'androidx.navigation.safeargs.kotlin' - -android { - compileSdkVersion 31 - buildToolsVersion '30.0.3' - defaultConfig { - applicationId 'com.example.app' - minSdkVersion 26 - targetSdkVersion 31 - versionCode 13 - versionName '0.0.1' - } - buildTypes { - debug { - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = '1.8' - // kotlinOptions.freeCompilerArgs = ['-Xinline-classes'] - } - buildFeatures.viewBinding = true - // We use the .filamat extension for materials compiled with matc - // Telling aapt to not compress them allows to load them efficiently - aaptOptions { - noCompress 'filamat', 'ktx' - } -} -kapt { - useBuildCache = false -} -dependencies { - implementation(fileTree(dir: "libs", include: ["*.jar"])) - - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - - api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' - api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2' - api 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.5.2' - - api 'androidx.appcompat:appcompat:1.3.1' - - implementation 'androidx.arch.core:core-common:2.1.0' - implementation 'androidx.arch.core:core-runtime:2.1.0' - - implementation 'androidx.vectordrawable:vectordrawable:1.1.0' - implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0' - - implementation 'androidx.dynamicanimation:dynamicanimation-ktx:1.0.0-alpha03' - - implementation 'androidx.interpolator:interpolator:1.0.0' - - api 'androidx.annotation:annotation:1.3.0' - - implementation 'androidx.palette:palette-ktx:1.0.0' - - api 'androidx.savedstate:savedstate:1.1.0' - - api 'androidx.autofill:autofill:1.1.0' - - api 'androidx.transition:transition:1.4.1' - - api 'androidx.biometric:biometric:1.1.0' - - api 'androidx.lifecycle:lifecycle-extensions:2.2.0' - api 'androidx.lifecycle:lifecycle-common-java8:2.4.0' - api 'androidx.lifecycle:lifecycle-livedata-core-ktx:2.4.0' - api 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0' - api 'androidx.lifecycle:lifecycle-reactivestreams-ktx:2.4.0' - api 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0' - api 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0' - - api 'androidx.work:work-runtime-ktx:2.7.0' - api 'androidx.work:work-gcm:2.7.0' - - implementation 'androidx.emoji:emoji:1.1.0' - implementation 'androidx.emoji:emoji-appcompat:1.1.0' - - api 'androidx.room:room-runtime:2.3.0' - api 'androidx.room:room-ktx:2.3.0' - kapt 'androidx.room:room-compiler:2.3.0' - - implementation 'androidx.sqlite:sqlite-ktx:2.1.0' - - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - - api 'androidx.constraintlayout:constraintlayout:2.1.1' - api 'androidx.recyclerview:recyclerview:1.2.1' - api 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' - api 'androidx.drawerlayout:drawerlayout:1.1.1' - api 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - api 'androidx.gridlayout:gridlayout:1.0.0' - api 'androidx.cardview:cardview:1.0.0' - api 'androidx.viewpager:viewpager:1.0.0' - api 'androidx.browser:browser:1.4.0' - - api 'androidx.core:core-ktx:1.7.0' - - api 'androidx.slice:slice-builders:1.1.0-alpha02' - api 'androidx.slice:slice-builders-ktx:1.0.0-alpha6' - - api 'androidx.slice:slice-core:1.1.0-alpha02' - api 'androidx.slice:slice-view:1.1.0-alpha02' - - // KTX Extensions - api 'androidx.core:core-ktx:1.7.0' - - api 'androidx.activity:activity-ktx:1.4.0' - - implementation 'androidx.benchmark:benchmark-junit4:1.0.0' - - implementation 'androidx.collection:collection-ktx:1.1.0' - - api 'androidx.fragment:fragment-ktx:1.4.0' - - api 'androidx.navigation:navigation-runtime-ktx:2.3.5' - api 'androidx.navigation:navigation-fragment-ktx:2.3.5' - api 'androidx.navigation:navigation-ui-ktx:2.3.5' - api 'androidx.navigation:navigation-dynamic-features-fragment:2.3.5' - - api 'androidx.paging:paging-common-ktx:3.1.0' - api 'androidx.paging:paging-runtime-ktx:3.1.0' - - implementation 'androidx.preference:preference-ktx:1.1.1' - - implementation 'com.google.android.play:core-ktx:1.8.1' - - api 'com.google.android.material:material:1.5.0-beta01' - - api 'com.google.ar:core:1.28.0' - - api 'com.google.android.filament:filament-android:1.14.0' - api 'com.google.android.filament:filament-utils-android:1.14.0' - api 'com.google.android.filament:gltfio-android:1.14.0' - - // Third Party Dependencies - - implementation 'io.arrow-kt:arrow-fx:0.12.1' -} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..82814d6 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,115 @@ +plugins { + alias(libs.plugins.androidApplication) + alias(libs.plugins.kotlinAndroid) + alias(libs.plugins.kotlinxParcelize) + alias(libs.plugins.kotlinxSerialization) + alias(libs.plugins.ksp) + alias(libs.plugins.hilt) +} + +kotlin { +} + +android { + namespace = "com.example.app" + compileSdk = libs.versions.compileSdk.get().toInt() + buildToolsVersion = libs.versions.buildToolsVersion.get() + + signingConfigs { + } + + defaultConfig { + applicationId = "com.example.app" + minSdk = libs.versions.minSdk.get().toInt() + targetSdk = libs.versions.targetSdk.get().toInt() + versionCode = 1 + versionName = "1.0.0" + + // reduces apk sizes by not including unsupported languages + resourceConfigurations += setOf("en") + + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + debug { + applicationIdSuffix = ".debug" + isMinifyEnabled = false + isShrinkResources = false + isDebuggable = true + } + } + + compileOptions { + isCoreLibraryDesugaringEnabled = true + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = libs.versions.jvmTarget.get() + + freeCompilerArgs = listOf( + "-opt-in=kotlinx.coroutines.FlowPreview", + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", +// "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", +// "-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi", +// "-opt-in=androidx.compose.material.ExperimentalMaterialApi", +// "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", +// "-opt-in=androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi", +// "-opt-in=androidx.compose.animation.ExperimentalAnimationApi", +// "-opt-in=androidx.compose.ui.text.ExperimentalTextApi", +// "-opt-in=androidx.compose.ui.ExperimentalComposeUiApi", +// "-opt-in=com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi", + ) + } + + buildFeatures { + viewBinding = true + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() + } + + packaging { + resources { + excludes += "/META-INF/versions/9/previous-compilation-data.bin" + } + } + + lint { + baseline = file("lint-baseline.xml") + } + + // We use the .filamat extension for materials compiled with matc + // Telling aapt to not compress them allows to load them efficiently + androidResources { + noCompress += listOf("filamat", "ktx") + } +} + +dependencies { + coreLibraryDesugaring(libs.desugarJdkLibs) + implementation(platform(libs.composeBom)) + + implementation(libs.hiltAndroid) + ksp(libs.hiltAndroidCompiler) + + implementation(libs.bundles.kotlinx) + implementation(libs.bundles.google) + implementation(libs.bundles.androidx) + implementation(libs.bundles.androidxApp) + implementation(libs.bundles.androidxCompose) + lintChecks(libs.composeLintChecks) + implementation(libs.bundles.filament) + implementation(libs.slf4jSimple) + + implementation(libs.arCore) + implementation(libs.arrowFx) + + testImplementation(libs.bundles.test) +} diff --git a/app/src/main/assets/materials/depth.filamat b/app/src/main/assets/materials/depth.filamat index 080f7dcb374079ff025710037a6282370520f80d..66fb7102cbd1a1e793328c40be716026219dc2e5 100644 GIT binary patch literal 23588 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 QD`WLrSu1DdtqalmKO!1cQvd(} literal 17797 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 MeH3y3^?C&U7kZSpod5s; diff --git a/app/src/main/assets/materials/flat.filamat b/app/src/main/assets/materials/flat.filamat index 61693a6f55d752fc318342984143e7fc9111fd02..1564ac489fa566491b2d1d936a42ca98a42ed269 100644 GIT binary patch literal 22070 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 Ra4tZ5pVECx_baIg^gVa@eFOji diff --git a/app/src/main/assets/materials/shadow.filamat b/app/src/main/assets/materials/shadow.filamat index f905d9f8cce39d0e22c4c0373acddaf44e0a8f2c..55c16dc038cdae46a7221ac556b6e26446585d27 100644 GIT binary patch literal 160840 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

T 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 z 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 K-+)4eGPeMn4?a== diff --git a/app/src/main/java/com/example/app/Matrix.kt b/app/src/main/java/com/example/app/Matrix.kt index 253fc0d..1f97ef5 100644 --- a/app/src/main/java/com/example/app/Matrix.kt +++ b/app/src/main/java/com/example/app/Matrix.kt @@ -1,5 +1,3 @@ -@file:Suppress("unused") - package com.example.app import android.app.Activity @@ -15,7 +13,10 @@ import java.nio.ByteOrder import java.nio.FloatBuffer import java.nio.ShortBuffer import java.nio.channels.Channels -import kotlin.math.* +import kotlin.math.PI +import kotlin.math.ceil +import kotlin.math.floor +import kotlin.math.sqrt inline val Float.Companion.size get() = java.lang.Float.BYTES @@ -29,21 +30,88 @@ inline val Float.clampToTau: Float when { this < 0f -> this + ceil(-this / Float.tau) * Float.tau + this >= Float.tau -> this - floor(this / Float.tau) * Float.tau + else -> this } -data class V2A(val floatArray: FloatArray) +data class V2A(val floatArray: FloatArray) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as V2A + + return floatArray.contentEquals(other.floatArray) + } + + override fun hashCode(): Int { + return floatArray.contentHashCode() + } +} + +data class V3(val floatArray: FloatArray) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false -data class V3(val floatArray: FloatArray) + other as V3 -data class V3A(val floatArray: FloatArray) + return floatArray.contentEquals(other.floatArray) + } + + override fun hashCode(): Int { + return floatArray.contentHashCode() + } +} + +data class V3A(val floatArray: FloatArray) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false -data class V4A(val floatArray: FloatArray) + other as V3A + + return floatArray.contentEquals(other.floatArray) + } + + override fun hashCode(): Int { + return floatArray.contentHashCode() + } +} -data class M4(val floatArray: FloatArray) +data class V4A(val floatArray: FloatArray) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as V4A + + return floatArray.contentEquals(other.floatArray) + } + + override fun hashCode(): Int { + return floatArray.contentHashCode() + } +} + +data class M4(val floatArray: FloatArray) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as M4 + + return floatArray.contentEquals(other.floatArray) + } + + override fun hashCode(): Int { + return floatArray.contentHashCode() + } +} @JvmInline value class TriangleIndexArray(val shortArray: ShortArray) @@ -82,14 +150,17 @@ fun M4.translate(x: Float, y: Float, z: Float): M4 = FloatArray(16) .also { Matrix.translateM(it, 0, floatArray, 0, x, y, z) } .let { M4(it) } +@Suppress("unused") fun M4.multiply(m: M4): M4 = FloatArray(16) .also { Matrix.multiplyMM(it, 0, floatArray, 0, m.floatArray, 0) } .let { M4(it) } +@Suppress("unused") fun M4.invert(): M4 = FloatArray(16) .also { Matrix.invertM(it, 0, floatArray, 0) } .let { M4(it) } +@Suppress("unused") fun m4Rotate(angle: Float, x: Float, y: Float, z: Float): M4 = FloatArray(16) .also { Matrix.setRotateM(it, 0, angle, x, y, z) } .let { M4(it) } @@ -102,7 +173,7 @@ fun FloatArray.toDoubleArray(): DoubleArray = DoubleArray(size) } fun Frame.projectionMatrix(): M4 = FloatArray(16) - .apply { camera.getProjectionMatrix(this, 0, ArCore.near, ArCore.far) } + .apply { camera.getProjectionMatrix(this, 0, ArCore.NEAR, ArCore.FAR) } .let { M4(it) } @Suppress("DEPRECATION") @@ -110,7 +181,7 @@ fun Activity.displayRotation(): Int = (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) display else windowManager.defaultDisplay)!!.rotation -@Suppress("DEPRECATION") +@Suppress("unused") fun Activity.displayRotationDegrees(): Int = when (displayRotation()) { Surface.ROTATION_0 -> 0 @@ -133,6 +204,8 @@ inline fun v2aCreate(count: Int, x: (Int) -> Float, y: (Int) -> Float): V2A = } const val dimenV2A: Int = 2 + +@Suppress("UnusedReceiverParameter") inline val V2A.dimen: Int get() = dimenV2A fun V2A.count(): Int = floatArray.size / dimen inline val V2A.indices: IntRange get() = IntRange(0, count() - 1) @@ -143,6 +216,8 @@ fun V2A.set(i: Int, x: Float, y: Float) { } const val dimenV3A: Int = 3 + +@Suppress("UnusedReceiverParameter") inline val V3A.dimen: Int get() = dimenV3A fun V3A.set(i: Int, x: Float, y: Float, z: Float) { @@ -158,12 +233,18 @@ fun mulV3(r: FloatArray, ri: Int, v: FloatArray, vi: Int, s: Float) { } const val dimenV4A: Int = 4 + +@Suppress("UnusedReceiverParameter") inline val V4A.dimen: Int get() = dimenV4A inline val V4A.count: Int get() = floatArray.size / dimen fun V4A.getX(i: Int): Float = floatArray[(i * dimen) + 0] + +@Suppress("unused") fun V4A.getY(i: Int): Float = floatArray[(i * dimen) + 1] fun V4A.getZ(i: Int): Float = floatArray[(i * dimen) + 2] + +@Suppress("unused") fun V4A.getW(i: Int): Float = floatArray[(i * dimen) + 3] fun V4A.set(i: Int, x: Float, y: Float, z: Float, w: Float) { @@ -185,8 +266,7 @@ fun V3.neg(): V3 = val v3Origin: V3 = v3(0f, 0f, 0f) -fun v3(x: Float, y: Float, z: Float): V3 = FloatArray(3) - .let { V3(it) } +fun v3(x: Float, y: Float, z: Float): V3 = V3(FloatArray(3)) .also { it.x = x it.y = y diff --git a/app/src/main/java/com/example/app/OpenGL.kt b/app/src/main/java/com/example/app/OpenGL.kt index b39bbad..7bbc207 100644 --- a/app/src/main/java/com/example/app/OpenGL.kt +++ b/app/src/main/java/com/example/app/OpenGL.kt @@ -1,6 +1,12 @@ package com.example.app -import android.opengl.* +import android.opengl.EGL14 +import android.opengl.EGLConfig +import android.opengl.EGLContext +import android.opengl.EGLDisplay +import android.opengl.EGLSurface +import android.opengl.GLES11Ext +import android.opengl.GLES30 import arrow.core.Either import arrow.core.left import arrow.core.right diff --git a/app/src/main/java/com/example/app/aractivity/ArActivity.kt b/app/src/main/java/com/example/app/aractivity/ArActivity.kt index ec04773..7007df1 100644 --- a/app/src/main/java/com/example/app/aractivity/ArActivity.kt +++ b/app/src/main/java/com/example/app/aractivity/ArActivity.kt @@ -6,27 +6,59 @@ import android.content.pm.PackageManager import android.content.res.Configuration import android.os.Build import android.os.Bundle -import android.view.* +import android.view.MotionEvent +import android.view.View +import android.view.WindowInsets +import android.view.WindowInsetsController import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.view.WindowCompat import androidx.core.view.isVisible -import com.example.app.* +import com.example.app.OpenGLVersionNotSupported +import com.example.app.PermissionResultEvent +import com.example.app.R +import com.example.app.UserCanceled import com.example.app.arcore.ArCore +import com.example.app.cameraPermissionRequestCode +import com.example.app.checkIfOpenGlVersionSupported import com.example.app.databinding.ExampleActivityBinding import com.example.app.filament.Filament -import com.example.app.gesture.* +import com.example.app.gesture.DragGesture +import com.example.app.gesture.DragGestureRecognizer +import com.example.app.gesture.PinchGesture +import com.example.app.gesture.PinchGestureRecognizer +import com.example.app.gesture.TransformationSystem +import com.example.app.gesture.TwistGesture +import com.example.app.gesture.TwistGestureRecognizer +import com.example.app.minOpenGlVersion +import com.example.app.renderer.FrameCallback +import com.example.app.renderer.LightRenderer +import com.example.app.renderer.ModelRenderer +import com.example.app.renderer.PlaneRenderer +import com.example.app.showOpenGlNotSupportedDialog import com.example.app.toRadians import com.example.app.x import com.example.app.y -import com.example.app.renderer.* import com.google.ar.core.ArCoreApk import com.google.ar.core.Plane import com.google.ar.core.TrackingState -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.dropWhile +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine import java.util.concurrent.TimeUnit import kotlin.coroutines.coroutineContext import kotlin.coroutines.resume @@ -424,7 +456,7 @@ class ArActivity : AppCompatActivity() { private suspend fun showCameraPermissionDialog(activity: AppCompatActivity) { if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) { - suspendCancellableCoroutine { continuation -> + suspendCancellableCoroutine { continuation -> val alertDialog = AlertDialog .Builder(activity) .setTitle(R.string.camera_permission_title) diff --git a/app/src/main/java/com/example/app/arcore/ArCore.kt b/app/src/main/java/com/example/app/arcore/ArCore.kt index 60f3a92..ff4a77c 100644 --- a/app/src/main/java/com/example/app/arcore/ArCore.kt +++ b/app/src/main/java/com/example/app/arcore/ArCore.kt @@ -2,6 +2,7 @@ package com.example.app.arcore import android.annotation.SuppressLint import android.app.Activity +import android.graphics.SurfaceTexture import android.hardware.camera2.CameraCharacteristics import android.hardware.camera2.CameraManager import android.media.Image @@ -13,13 +14,38 @@ import android.view.View import android.widget.FrameLayout import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams -import com.example.app.* +import com.example.app.M4 +import com.example.app.V2A +import com.example.app.count +import com.example.app.createExternalTextureId +import com.example.app.dimenV2A import com.example.app.filament.Filament -import com.google.android.filament.* +import com.example.app.m4Identity +import com.example.app.matrix +import com.example.app.projectionMatrix +import com.example.app.readUncompressedAsset +import com.example.app.rotate +import com.example.app.set +import com.example.app.toDoubleArray +import com.example.app.toFloatBuffer +import com.example.app.toShortBuffer +import com.example.app.translate +import com.google.android.filament.Entity +import com.google.android.filament.EntityManager +import com.google.android.filament.IndexBuffer +import com.google.android.filament.Material +import com.google.android.filament.MaterialInstance +import com.google.android.filament.RenderableManager import com.google.android.filament.RenderableManager.PrimitiveType +import com.google.android.filament.Stream +import com.google.android.filament.Texture +import com.google.android.filament.TextureSampler +import com.google.android.filament.VertexBuffer import com.google.android.filament.VertexBuffer.AttributeType import com.google.android.filament.VertexBuffer.VertexAttribute -import com.google.ar.core.* +import com.google.ar.core.Config +import com.google.ar.core.Frame +import com.google.ar.core.Session import kotlin.math.roundToInt class ModelBuffers(val clipPosition: V2A, val uvs: V2A, val triangleIndices: ShortArray) @@ -27,10 +53,10 @@ class ModelBuffers(val clipPosition: V2A, val uvs: V2A, val triangleIndices: Sho @SuppressLint("MissingPermission") class ArCore(private val activity: Activity, val filament: Filament, private val view: View) { companion object { - const val near: Float = 0.1f - const val far: Float = 30f - private const val positionBufferIndex: Int = 0 - private const val uvBufferIndex: Int = 1 + const val NEAR: Float = 0.1f + const val FAR: Float = 30f + private const val POSITION_BUFFER_INDEX: Int = 0 + private const val UV_BUFFER_INDEX: Int = 1 } private val cameraStreamTextureId: Int = createExternalTextureId() @@ -80,7 +106,7 @@ class ArCore(private val activity: Activity, val filament: Filament, private val session.close() } - var displayRotationDegrees: Int = 0 + private var displayRotationDegrees: Int = 0 fun configurationChange() { if (this::frame.isInitialized.not()) return @@ -127,16 +153,19 @@ class ArCore(private val activity: Activity, val filament: Filament, private val cameraWidth = dimensions[0] cameraHeight = dimensions[1] } + else -> { cameraWidth = dimensions[1] cameraHeight = dimensions[0] } } + else -> when (displayRotation) { Surface.ROTATION_0, Surface.ROTATION_180 -> { cameraWidth = dimensions[1] cameraHeight = dimensions[0] } + else -> { cameraWidth = dimensions[0] cameraHeight = dimensions[1] @@ -168,7 +197,7 @@ class ArCore(private val activity: Activity, val filament: Filament, private val session.setDisplayGeometry(displayRotation, viewWidth, viewHeight) } - var hasDepthImage: Boolean = false + private var hasDepthImage: Boolean = false fun update(frame: Frame, filament: Filament) { val firstFrame = this::frame.isInitialized.not() @@ -184,7 +213,7 @@ class ArCore(private val activity: Activity, val filament: Filament, private val stream = Stream .Builder() - .stream(cameraStreamTextureId.toLong()) + .stream(SurfaceTexture(cameraStreamTextureId)) .width(width) .height(height) .build(filament.engine) @@ -231,7 +260,7 @@ class ArCore(private val activity: Activity, val filament: Filament, private val ?.let { if (hasDepthImage.not()) { try { - val depthImage = frame.acquireDepthImage() as ArImage + val depthImage = frame.acquireDepthImage16Bits() if (depthImage.planes[0].buffer[0] != 0.toByte()) { hasDepthImage = true @@ -293,8 +322,8 @@ class ArCore(private val activity: Activity, val filament: Filament, private val // update camera projection filament.camera.setCustomProjection( frame.projectionMatrix().floatArray.toDoubleArray(), - near.toDouble(), - far.toDouble(), + NEAR.toDouble(), + FAR.toDouble(), ) val cameraTransform = frame.camera.displayOrientedPose.matrix() @@ -320,14 +349,14 @@ class ArCore(private val activity: Activity, val filament: Filament, private val .bufferCount(2) .attribute( VertexAttribute.POSITION, - positionBufferIndex, + POSITION_BUFFER_INDEX, AttributeType.FLOAT2, 0, 0, ) .attribute( VertexAttribute.UV0, - uvBufferIndex, + UV_BUFFER_INDEX, AttributeType.FLOAT2, 0, 0, @@ -336,13 +365,13 @@ class ArCore(private val activity: Activity, val filament: Filament, private val .also { vertexBuffer -> vertexBuffer.setBufferAt( filament.engine, - positionBufferIndex, + POSITION_BUFFER_INDEX, tes.clipPosition.floatArray.toFloatBuffer(), ) vertexBuffer.setBufferAt( filament.engine, - uvBufferIndex, + UV_BUFFER_INDEX, tes.uvs.floatArray.toFloatBuffer(), ) }, @@ -423,14 +452,14 @@ class ArCore(private val activity: Activity, val filament: Filament, private val .bufferCount(2) .attribute( VertexAttribute.POSITION, - positionBufferIndex, + POSITION_BUFFER_INDEX, AttributeType.FLOAT2, 0, 0, ) .attribute( VertexAttribute.UV0, - uvBufferIndex, + UV_BUFFER_INDEX, AttributeType.FLOAT2, 0, 0, @@ -439,13 +468,13 @@ class ArCore(private val activity: Activity, val filament: Filament, private val .also { vertexBuffer -> vertexBuffer.setBufferAt( filament.engine, - positionBufferIndex, + POSITION_BUFFER_INDEX, tes.clipPosition.floatArray.toFloatBuffer() ) vertexBuffer.setBufferAt( filament.engine, - uvBufferIndex, + UV_BUFFER_INDEX, tes.uvs.floatArray.toFloatBuffer() ) }, @@ -460,17 +489,16 @@ class ArCore(private val activity: Activity, val filament: Filament, private val .build(filament.engine, EntityManager.get().create().also { depthRenderable = it }) } + @Suppress("KotlinConstantConditions") private fun tessellation(): ModelBuffers { - val tesWidth: Int = 1 - val tesHeight: Int = 1 + val tesWidth = 1 + val tesHeight = 1 - val clipPosition: V2A = (((tesWidth * tesHeight) + tesWidth + tesHeight + 1) * dimenV2A) - .let { FloatArray(it) } - .let { V2A(it) } + val clipPosition = + V2A(FloatArray((((tesWidth * tesHeight) + tesWidth + tesHeight + 1) * dimenV2A))) - val uvs: V2A = (((tesWidth * tesHeight) + tesWidth + tesHeight + 1) * dimenV2A) - .let { FloatArray(it) } - .let { V2A(it) } + val uvs = + V2A(FloatArray((((tesWidth * tesHeight) + tesWidth + tesHeight + 1) * dimenV2A))) for (k in 0..tesHeight) { val v = k.toFloat() / tesHeight.toFloat() diff --git a/app/src/main/java/com/example/app/filament/Filament.kt b/app/src/main/java/com/example/app/filament/Filament.kt index 3140f9a..35b0425 100644 --- a/app/src/main/java/com/example/app/filament/Filament.kt +++ b/app/src/main/java/com/example/app/filament/Filament.kt @@ -6,12 +6,19 @@ import android.view.Surface import android.view.SurfaceView import com.example.app.createEglContext import com.example.app.destroyEglContext -import com.google.android.filament.* +import com.google.android.filament.Camera +import com.google.android.filament.Engine +import com.google.android.filament.EntityManager +import com.google.android.filament.Renderer +import com.google.android.filament.Scene +import com.google.android.filament.SwapChain +import com.google.android.filament.View +import com.google.android.filament.Viewport import com.google.android.filament.android.DisplayHelper import com.google.android.filament.android.UiHelper import com.google.android.filament.gltfio.AssetLoader import com.google.android.filament.gltfio.ResourceLoader -import com.google.android.filament.gltfio.UbershaderLoader +import com.google.android.filament.gltfio.UbershaderProvider class Filament(context: Context, val surfaceView: SurfaceView) { var timestamp: Long = 0L @@ -37,7 +44,7 @@ class Filament(context: Context, val surfaceView: SurfaceView) { } val assetLoader = - AssetLoader(engine, UbershaderLoader(engine), EntityManager.get()) + AssetLoader(engine, UbershaderProvider(engine), EntityManager.get()) val resourceLoader = ResourceLoader(engine) diff --git a/app/src/main/java/com/example/app/gesture/BaseGestureRecognizer.kt b/app/src/main/java/com/example/app/gesture/BaseGestureRecognizer.kt index 9c3346c..22448ab 100644 --- a/app/src/main/java/com/example/app/gesture/BaseGestureRecognizer.kt +++ b/app/src/main/java/com/example/app/gesture/BaseGestureRecognizer.kt @@ -1,7 +1,6 @@ package com.example.app.gesture import android.view.MotionEvent -import java.util.* // A Gesture recognizer processes touch input to determine if a gesture should start and fires an // event when the gesture is started. @@ -20,6 +19,7 @@ abstract class BaseGestureRecognizer>(val gesturePointersUtil } } + @Suppress("unused") fun removeOnGestureStartedListener(listener: OnGestureStartedListener) { gestureStartedListeners.remove(listener) } diff --git a/app/src/main/java/com/example/app/gesture/DragGesture.kt b/app/src/main/java/com/example/app/gesture/DragGesture.kt index 454d775..33c5a29 100644 --- a/app/src/main/java/com/example/app/gesture/DragGesture.kt +++ b/app/src/main/java/com/example/app/gesture/DragGesture.kt @@ -1,7 +1,11 @@ package com.example.app.gesture import android.view.MotionEvent -import com.example.app.* +import com.example.app.V3 +import com.example.app.eq +import com.example.app.magnitude +import com.example.app.sub +import com.example.app.v3Origin class DragGesture(gesturePointersUtility: GesturePointersUtility, motionEvent: MotionEvent) : BaseGesture(gesturePointersUtility) { diff --git a/app/src/main/java/com/example/app/gesture/GesturePointersUtility.kt b/app/src/main/java/com/example/app/gesture/GesturePointersUtility.kt index 96f8b99..f447a6b 100644 --- a/app/src/main/java/com/example/app/gesture/GesturePointersUtility.kt +++ b/app/src/main/java/com/example/app/gesture/GesturePointersUtility.kt @@ -5,7 +5,6 @@ import android.util.TypedValue import android.view.MotionEvent import com.example.app.V3 import com.example.app.v3 -import java.util.* // Retains/Releases pointer Ids so that each pointer can only be used in one gesture at a time. // Provides helper functions for converting touch coordinates between pixels and inches. diff --git a/app/src/main/java/com/example/app/gesture/PinchGesture.kt b/app/src/main/java/com/example/app/gesture/PinchGesture.kt index 7befa28..50925ee 100644 --- a/app/src/main/java/com/example/app/gesture/PinchGesture.kt +++ b/app/src/main/java/com/example/app/gesture/PinchGesture.kt @@ -1,7 +1,14 @@ package com.example.app.gesture import android.view.MotionEvent -import com.example.app.* +import com.example.app.V3 +import com.example.app.dot +import com.example.app.eq +import com.example.app.magnitude +import com.example.app.neg +import com.example.app.normalize +import com.example.app.sub +import com.example.app.v3Origin import kotlin.math.abs import kotlin.math.cos @@ -28,12 +35,10 @@ class PinchGesture( private var previousPosition1: V3 = startPosition1 private var previousPosition2: V3 = startPosition2 - var gap = 0f - private set - - var gapDelta = 0f - private set + private var gap = 0f + private var gapDelta = 0f + @Suppress("unused") fun gapInches(): Float { return gesturePointersUtility.pixelsToInches(gap) } diff --git a/app/src/main/java/com/example/app/gesture/TwistGesture.kt b/app/src/main/java/com/example/app/gesture/TwistGesture.kt index 7b14157..e8a98b5 100644 --- a/app/src/main/java/com/example/app/gesture/TwistGesture.kt +++ b/app/src/main/java/com/example/app/gesture/TwistGesture.kt @@ -1,7 +1,15 @@ package com.example.app.gesture import android.view.MotionEvent -import com.example.app.* +import com.example.app.V3 +import com.example.app.dot +import com.example.app.eq +import com.example.app.normalize +import com.example.app.sub +import com.example.app.toDegrees +import com.example.app.v3Origin +import com.example.app.x +import com.example.app.y import kotlin.math.abs import kotlin.math.acos import kotlin.math.sign diff --git a/app/src/main/java/com/example/app/renderer/FrameCallback.kt b/app/src/main/java/com/example/app/renderer/FrameCallback.kt index b1e7ee6..02ba123 100644 --- a/app/src/main/java/com/example/app/renderer/FrameCallback.kt +++ b/app/src/main/java/com/example/app/renderer/FrameCallback.kt @@ -10,13 +10,14 @@ class FrameCallback( private val doFrame: (frame: Frame) -> Unit, ) : Choreographer.FrameCallback { companion object { - private const val maxFramesPerSecond: Long = 60 + private const val MAX_FRAMES_PER_SECOND: Long = 60 } - sealed class FrameRate(val factor: Long) { - object Full : FrameRate(1) - object Half : FrameRate(2) - object Third : FrameRate(3) + @Suppress("unused") + enum class FrameRate(val factor: Long) { + Full(1), + Half(2), + Third(3), } private val choreographer: Choreographer = Choreographer.getInstance() @@ -28,7 +29,7 @@ class FrameCallback( // limit to max fps val nanoTime = System.nanoTime() - val tick = nanoTime / (TimeUnit.SECONDS.toNanos(1) / maxFramesPerSecond) + val tick = nanoTime / (TimeUnit.SECONDS.toNanos(1) / MAX_FRAMES_PER_SECOND) if (lastTick / frameRate.factor == tick / frameRate.factor) { return diff --git a/app/src/main/java/com/example/app/renderer/LightRenderer.kt b/app/src/main/java/com/example/app/renderer/LightRenderer.kt index 5493910..6d24e26 100644 --- a/app/src/main/java/com/example/app/renderer/LightRenderer.kt +++ b/app/src/main/java/com/example/app/renderer/LightRenderer.kt @@ -3,9 +3,16 @@ package com.example.app.renderer import android.content.Context import android.content.res.AssetManager import android.graphics.BitmapFactory -import com.example.app.* +import com.example.app.V3 +import com.example.app.div import com.example.app.filament.Filament -import com.google.android.filament.* +import com.example.app.getEnvironmentalHdrSphericalHarmonics +import com.google.android.filament.Engine +import com.google.android.filament.EntityInstance +import com.google.android.filament.EntityManager +import com.google.android.filament.IndirectLight +import com.google.android.filament.LightManager +import com.google.android.filament.Texture import com.google.ar.core.Frame import com.google.ar.core.LightEstimate import java.nio.ByteBuffer @@ -31,7 +38,6 @@ class LightRenderer(context: Context, private val filament: Filament) { filament.engine.lightManager.getInstance(directionalLight) } - fun doFrame(frame: Frame) { // update lighting estimate if (frame.lightEstimate.state != LightEstimate.State.VALID) { @@ -77,6 +83,7 @@ class LightRenderer(context: Context, private val filament: Filament) { } } +@Suppress("SameParameterValue") private fun peekSize(assets: AssetManager, name: String): Pair { assets.open(name).use { input -> val opts = BitmapFactory.Options().apply { inJustDecodeBounds = true } diff --git a/app/src/main/java/com/example/app/renderer/ModelRenderer.kt b/app/src/main/java/com/example/app/renderer/ModelRenderer.kt index 0f5a0ad..e28e33c 100644 --- a/app/src/main/java/com/example/app/renderer/ModelRenderer.kt +++ b/app/src/main/java/com/example/app/renderer/ModelRenderer.kt @@ -1,15 +1,33 @@ package com.example.app.renderer import android.content.Context -import com.example.app.* +import com.example.app.V3 import com.example.app.aractivity.ScreenPosition import com.example.app.arcore.ArCore +import com.example.app.clampToTau import com.example.app.filament.Filament +import com.example.app.m4Identity +import com.example.app.rotate +import com.example.app.scale +import com.example.app.toDegrees +import com.example.app.translate +import com.example.app.v3Origin +import com.example.app.x +import com.example.app.y +import com.example.app.z import com.google.ar.core.Frame import com.google.ar.core.Point -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.nio.ByteBuffer import java.util.concurrent.TimeUnit @@ -39,13 +57,12 @@ class ModelRenderer(context: Context, private val arCore: ArCore, private val fi coroutineScope.launch { val filamentAsset = withContext(Dispatchers.IO) { - @Suppress("BlockingMethodInNonBlockingContext") context.assets .open("eren-hiphop-dance.glb") .use { input -> val bytes = ByteArray(input.available()) input.read(bytes) - filament.assetLoader.createAssetFromBinary(ByteBuffer.wrap(bytes))!! + filament.assetLoader.createAsset(ByteBuffer.wrap(bytes))!! } } .also { filament.resourceLoader.loadResources(it) } @@ -92,7 +109,7 @@ class ModelRenderer(context: Context, private val arCore: ArCore, private val fi doFrameEvents.collect { frame -> // update animator - val animator = filamentAsset.animator + val animator = filamentAsset.instance.animator if (animator.animationCount > 0) { animator.applyAnimation( diff --git a/app/src/main/java/com/example/app/renderer/PlaneRenderer.kt b/app/src/main/java/com/example/app/renderer/PlaneRenderer.kt index 7d6e668..4f254da 100644 --- a/app/src/main/java/com/example/app/renderer/PlaneRenderer.kt +++ b/app/src/main/java/com/example/app/renderer/PlaneRenderer.kt @@ -1,12 +1,29 @@ package com.example.app.renderer import android.content.Context -import com.example.app.* import com.example.app.R +import com.example.app.count +import com.example.app.dimenV2A +import com.example.app.dimenV4A import com.example.app.filament.Filament -import com.google.android.filament.* -import com.google.android.filament.textured.TextureType -import com.google.android.filament.textured.loadTexture +import com.example.app.horizontalToUV +import com.example.app.matrix +import com.example.app.polygonToUV +import com.example.app.polygonToVertices +import com.example.app.readUncompressedAsset +import com.example.app.size +import com.example.app.triangleIndexArrayCreate +import com.google.android.filament.Box +import com.google.android.filament.Entity +import com.google.android.filament.EntityManager +import com.google.android.filament.IndexBuffer +import com.google.android.filament.Material +import com.google.android.filament.MaterialInstance +import com.google.android.filament.RenderableManager +import com.google.android.filament.TextureSampler +import com.google.android.filament.VertexBuffer +import com.google.android.filament.utils.TextureType +import com.google.android.filament.utils.loadTexture import com.google.ar.core.Frame import com.google.ar.core.Plane import com.google.ar.core.TrackingState @@ -19,8 +36,8 @@ import kotlin.math.min class PlaneRenderer(context: Context, private val filament: Filament) { companion object { - private const val planeVertexBufferSize: Int = 1000 - private const val planeIndexBufferSize: Int = (planeVertexBufferSize - 2) * 3 + private const val PLANE_VERTEX_BUFFER_SIZE: Int = 1000 + private const val PLANE_INDEX_BUFFER_SIZE: Int = (PLANE_VERTEX_BUFFER_SIZE - 2) * 3 } private val textureMaterial: Material = context @@ -41,7 +58,7 @@ class PlaneRenderer(context: Context, private val filament: Filament) { TextureSampler().also { it.anisotropy = 8.0f }, ) - materialInstance.setParameter("alpha", 1f) +// materialInstance.setParameter("alpha", 1f) } private val shadowMaterial: Material = context @@ -54,21 +71,21 @@ class PlaneRenderer(context: Context, private val filament: Filament) { } private val planeVertexFloatBuffer: FloatBuffer = ByteBuffer - .allocateDirect(planeVertexBufferSize * dimenV4A * Float.size) + .allocateDirect(PLANE_VERTEX_BUFFER_SIZE * dimenV4A * Float.size) .order(ByteOrder.nativeOrder()) .asFloatBuffer() private val planeUvFloatBuffer: FloatBuffer = ByteBuffer - .allocateDirect(planeVertexBufferSize * dimenV2A * Float.size) + .allocateDirect(PLANE_VERTEX_BUFFER_SIZE * dimenV2A * Float.size) .order(ByteOrder.nativeOrder()) .asFloatBuffer() private val planeIndexShortBuffer: ShortBuffer = ShortBuffer - .allocate(planeIndexBufferSize) + .allocate(PLANE_INDEX_BUFFER_SIZE) private val planeVertexBuffer: VertexBuffer = VertexBuffer .Builder() - .vertexCount(planeVertexBufferSize) + .vertexCount(PLANE_VERTEX_BUFFER_SIZE) .bufferCount(2) .attribute( VertexBuffer.VertexAttribute.POSITION, @@ -88,7 +105,7 @@ class PlaneRenderer(context: Context, private val filament: Filament) { private val planeIndexBuffer: IndexBuffer = IndexBuffer .Builder() - .indexCount(planeIndexBufferSize) + .indexCount(PLANE_INDEX_BUFFER_SIZE) .bufferType(IndexBuffer.Builder.IndexType.USHORT) .build(filament.engine) @@ -116,8 +133,8 @@ class PlaneRenderer(context: Context, private val filament: Filament) { var zMin = Float.POSITIVE_INFINITY var zMax = Float.NEGATIVE_INFINITY - var vertexBufferOffset: Int = 0 - var indexBufferOffset: Int = 0 + var vertexBufferOffset = 0 + var indexBufferOffset = 0 var indexWithoutShadow: Int? = null @@ -146,8 +163,8 @@ class PlaneRenderer(context: Context, private val filament: Filament) { ) // check for for buffer overflow - if (vertexBufferOffset + planeVertices.count > planeVertexBufferSize || - indexBufferOffset + planeTriangleIndices.shortArray.count() > planeIndexBufferSize + if (vertexBufferOffset + planeVertices.count > PLANE_VERTEX_BUFFER_SIZE || + indexBufferOffset + planeTriangleIndices.shortArray.count() > PLANE_INDEX_BUFFER_SIZE ) { break } diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 232af48..0000000 --- a/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext { - kotlin_version = '1.5.31' - } - repositories { - google() - mavenCentral() - maven { url 'https://plugins.gradle.org/m2/' } - maven { url 'https://dl.bintray.com/arrow-kt/arrow-kt/' } - } - dependencies { - classpath 'com.android.tools.build:gradle:7.0.3' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" - classpath 'com.google.gms:google-services:4.3.10' - classpath 'com.google.firebase:perf-plugin:1.4.0' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.0' - classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5' - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..827982b --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,62 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + alias(libs.plugins.kotlinAndroid) apply false + alias(libs.plugins.kotlinxSerialization) apply false + alias(libs.plugins.kotlinxParcelize) apply false + alias(libs.plugins.androidApplication) apply false + alias(libs.plugins.ksp) apply false + alias(libs.plugins.hilt) apply false +} + +tasks.register("clean", Delete::class) { + delete(rootProject.layout.buildDirectory) +} + +subprojects { + tasks.withType().configureEach { + kotlinOptions { + freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers" + + if (project.findProperty("hackernews.enableComposeCompilerReports") == "true") { + // force tasks to rerun so that metrics are generated + outputs.upToDateWhen { false } + freeCompilerArgs = freeCompilerArgs + + "-P=plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.projectDir.absolutePath}/build/compose_metrics/" + + "-P=plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.projectDir.absolutePath}/build/compose_metrics/" + } + } + } +} + +//buildscript { +// ext { +// kotlin_version = "1.5.31" +// } +// repositories { +// google() +// mavenCentral() +// maven { url "https://plugins.gradle.org/m2/" } +// maven { url "https://dl.bintray.com/arrow-kt/arrow-kt/" } +// } +// dependencies { +// classpath "com.android.tools.build:gradle:7.0.3" +// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" +// classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" +// classpath "com.google.gms:google-services:4.3.10" +// classpath "com.google.firebase:perf-plugin:1.4.0" +// classpath "com.google.firebase:firebase-crashlytics-gradle:2.8.0" +// classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5" +// } +//} +// +//allprojects { +// repositories { +// google() +// mavenCentral() +// } +//} +// +//task clean(type: Delete) { +// delete rootProject.buildDir +//} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..7211269 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,186 @@ +[versions] +jvmTarget = "17" +compileSdk = "34" +targetSdk = "34" +minSdk = "26" +buildToolsVersion = "34.0.0" +composeCompiler = "1.5.8" +android = "8.3.0-rc01" +kotlin = "1.9.22" +ksp = "1.9.22-1.0.17" +kotlinxCoroutines = "1.7.3" +kotlinxSerialization = "1.6.2" +kotlinxCollectionsImmutable = "0.3.7" +kotlinxDatetime = "0.5.0" +activityKtx = "1.8.2" +fragmentKtx = "1.6.2" +lifecycle = "2.7.0" +navigation = "2.7.6" +hilt = "2.50" +window = "1.2.0" +appcompat = "1.6.1" +coreKtx = "1.12.0" +collectionKtx = "1.4.0" +paletteKtx = "1.0.0" +workRuntimeKtx = "2.9.0" +preferenceKtx = "1.2.1" +hiltNavigationCompose = "1.1.0" +composeLintChecks = "1.3.1" +material3 = "1.2.0-rc01" +composeBom = "2024.01.00" +uiTestJunit4 = "1.6.0" +slf4jSimple = "2.0.11" +junit = "4.13.2" +junitExt = "1.1.5" +desugarJdkLibs = "2.0.4" +arCore = "1.41.0" +filamentAndroid = "1.49.3" +arrowFx = "0.12.1" +coil = "2.5.0" +mockk = "1.13.9" + +[plugins] +kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlinxSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +kotlinxParcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } +androidApplication = { id = "com.android.application", version.ref = "android" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } + +[bundles] +kotlinx = [ + "kotlinxCoroutinesAndroid", + "kotlinxSerializationJson", + "kotlinxCollectionsImmutable", + "kotlinxDatetime", +] +google = [ + "kspSymbolProcessingApi", +] +androidx = [ + "coreKtx", + "collectionKtx", + "appcompat", + "window", + "activityKtx", + "activityCompose", + "fragmentKtx", + "paletteKtx", + "workRuntimeKtx", + "preferenceKtx", + "lifecycleProcess", + "lifecycleRuntimeKtx", + "lifecycleRuntimeCompose", + "lifecycleViewModelKtx", + "lifecycleViewModelCompose", + "lifecycleViewModelSavedState", +] +androidxApp = [ + "navigationRuntimeKtx", + "navigationUiKtx", + "navigationCompose", + "composeMaterial", +] +androidxCompose = [ + "ui", + "uiViewBinding", + "uiTooling", + "uiToolingData", + "uiToolingPreview", + "uiUtil", + "material3", + "material3WindowSize", + "materialIconsCore", + "materialIconsExtended", + "foundation", + "uiTextGoogleFonts", + "coilCompose", +] +filament = [ + "filament-android", + "filament-utils-android", + "gltfio-android" +] +test = [ + "kotlinTest", + "kotlinxCoroutinesTest", + "uiTestJunit4", + "junit", + "junitExt", + "mockk", + "uiTestManifest", +] + +[libraries] +kotlinTest = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" } +kotlinxCoroutinesAndroid = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } +kotlinxCoroutinesTest = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } +kotlinxSerializationJson = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } +kotlinxCollectionsImmutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" } +kotlinxDatetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } + +desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugarJdkLibs" } + +kspSymbolProcessingApi = { group = "com.google.devtools.ksp", name = "symbol-processing-api", version.ref = "ksp" } + +window = { group = "androidx.window", name = "window", version.ref = "window" } +appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +coreKtx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +collectionKtx = { group = "androidx.collection", name = "collection-ktx", version.ref = "collectionKtx" } +activityKtx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityKtx" } +activityCompose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityKtx" } +fragmentKtx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragmentKtx" } +paletteKtx = { group = "androidx.palette", name = "palette-ktx", version.ref = "paletteKtx" } +workRuntimeKtx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workRuntimeKtx" } +preferenceKtx = { group = "androidx.preference", name = "preference-ktx", version.ref = "preferenceKtx" } + +lifecycleProcess = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "lifecycle" } +lifecycleRuntimeKtx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } +lifecycleViewModelKtx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" } +lifecycleRuntimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" } +lifecycleViewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" } +lifecycleViewModelSavedState = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-savedstate", version.ref = "lifecycle" } + +navigationRuntimeKtx = { group = "androidx.navigation", name = "navigation-runtime-ktx", version.ref = "navigation" } + +hiltAndroid = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } +hiltAndroidCompiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" } +hiltNavigationCompose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" } + +navigationUiKtx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigation" } +navigationCompose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } + +composeLintChecks = { group = "com.slack.lint.compose", name = "compose-lint-checks", version.ref = "composeLintChecks" } + +material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" } + +composeBom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +material3WindowSize = { group = "androidx.compose.material3", name = "material3-window-size-class" } +ui = { group = "androidx.compose.ui", name = "ui" } +uiViewBinding = { group = "androidx.compose.ui", name = "ui-viewbinding" } +uiTooling = { group = "androidx.compose.ui", name = "ui-tooling" } +uiToolingData = { group = "androidx.compose.ui", name = "ui-tooling-data" } +uiToolingPreview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +uiUtil = { group = "androidx.compose.ui", name = "ui-util" } +composeMaterial = { group = "androidx.compose.material", name = "material" } +materialIconsCore = { group = "androidx.compose.material", name = "material-icons-core" } +materialIconsExtended = { group = "androidx.compose.material", name = "material-icons-extended" } +foundation = { group = "androidx.compose.foundation", name = "foundation" } +uiTextGoogleFonts = { group = "androidx.compose.ui", name = "ui-text-google-fonts" } +uiTestJunit4 = { group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "uiTestJunit4" } +uiTestManifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } + +arCore = { module = "com.google.ar:core", version.ref = "arCore" } +arrowFx = { module = "io.arrow-kt:arrow-fx", version.ref = "arrowFx" } + +slf4jSimple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4jSimple" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +junitExt = { group = "androidx.test.ext", name = "junit", version.ref = "junitExt" } + +coilCompose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } + +filament-android = { module = "com.google.android.filament:filament-android", version.ref = "filamentAndroid" } +filament-utils-android = { module = "com.google.android.filament:filament-utils-android", version.ref = "filamentAndroid" } +gltfio-android = { module = "com.google.android.filament:gltfio-android", version.ref = "filamentAndroid" } + +mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e1efd6d..dd08087 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 204a2ca..0000000 --- a/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name='AR Core Filament Example App' -include ':app' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..73e417d --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,21 @@ +@file:Suppress("UnstableApiUsage") + +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "AR Core Filament Example App" +include(":app")