From 22dd7d86570b7ab328117ef31d183575de0bdd56 Mon Sep 17 00:00:00 2001 From: Jan Szymanski Date: Wed, 1 Jul 2020 20:57:39 +0100 Subject: [PATCH] Convert MaterialFactory to coroutines --- .../magmolecular/ar/MagMolActivity.kt | 6 +- .../plweegie/magmolecular/utils/ArMolecule.kt | 17 +- sceneformsrc/sceneform/build.gradle | 13 +- .../sceneform/rendering/MaterialFactory.java | 201 ------------------ .../ar/sceneform/rendering/MaterialFactory.kt | 170 +++++++++++++++ 5 files changed, 195 insertions(+), 212 deletions(-) delete mode 100644 sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.java create mode 100644 sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.kt diff --git a/app/src/main/java/com/plweegie/magmolecular/ar/MagMolActivity.kt b/app/src/main/java/com/plweegie/magmolecular/ar/MagMolActivity.kt index 750b891..b0e3d4f 100644 --- a/app/src/main/java/com/plweegie/magmolecular/ar/MagMolActivity.kt +++ b/app/src/main/java/com/plweegie/magmolecular/ar/MagMolActivity.kt @@ -62,7 +62,7 @@ class MagMolActivity : AppCompatActivity() { } } - private suspend fun parseSmiles(smiles: String?) { + private suspend fun parseSmiles(smiles: String?) { loading_pb?.visibility = View.VISIBLE try { @@ -73,9 +73,9 @@ class MagMolActivity : AppCompatActivity() { addCenterOfMass(Vector3(arMolecule.centerCoordX, arMolecule.centerCoordY, arMolecule.centerCoordZ)) - arMolecule.renderableAtoms.forEach { (atom, material) -> + arMolecule.getRenderableAtoms().forEach { (atom, material) -> val coords = Vector3(atom.xCoord, atom.yCoord, atom.zCoord) - renderAtom(coords, material.await()) + renderAtom(coords, material) } } catch (e: InvalidSmilesException) { Toast.makeText(this, "Invalid SMILES", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/plweegie/magmolecular/utils/ArMolecule.kt b/app/src/main/java/com/plweegie/magmolecular/utils/ArMolecule.kt index aa09f32..6f31197 100644 --- a/app/src/main/java/com/plweegie/magmolecular/utils/ArMolecule.kt +++ b/app/src/main/java/com/plweegie/magmolecular/utils/ArMolecule.kt @@ -3,8 +3,8 @@ package com.plweegie.magmolecular.utils import android.content.Context import com.google.ar.sceneform.rendering.Material import com.google.ar.sceneform.rendering.MaterialFactory -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.future.asDeferred +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import org.openscience.cdk.interfaces.IAtom @@ -20,12 +20,15 @@ class ArMolecule(atoms: List, private val context: Context) { } } - private val materials: List> = arAtoms.map { - getMaterialAsync(it.color) + private suspend fun getMaterials(): List = coroutineScope { + arAtoms.map { + val material = async { getMaterialAsync(it.color) } + material.await() + } } - val renderableAtoms: List>> = arAtoms zip materials + suspend fun getRenderableAtoms(): List> = arAtoms zip getMaterials() - private fun getMaterialAsync(color: Int): Deferred = - MaterialFactory.makeOpaqueWithColor(context, com.google.ar.sceneform.rendering.Color(color)).asDeferred() + private suspend fun getMaterialAsync(color: Int): Material = + MaterialFactory.makeOpaqueWithColor(context, com.google.ar.sceneform.rendering.Color(color)) } \ No newline at end of file diff --git a/sceneformsrc/sceneform/build.gradle b/sceneformsrc/sceneform/build.gradle index b7e2409..64a3fc2 100644 --- a/sceneformsrc/sceneform/build.gradle +++ b/sceneformsrc/sceneform/build.gradle @@ -13,6 +13,7 @@ * limitations under the License. */ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' android { compileSdkVersion 29 @@ -43,7 +44,17 @@ dependencies { api 'com.google.android.filament:filament-android:1.7.0' api 'com.google.android.filament:gltfio-android:1.7.0' - api "com.google.ar:core:1.17.0" + api "com.google.ar:core:1.18.0" implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.core:core-ktx:1.3.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.7' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.3.7' +} +repositories { + mavenCentral() } diff --git a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.java b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.java deleted file mode 100644 index 2d024e4..0000000 --- a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.google.ar.sceneform.rendering; - -import android.content.Context; -import android.os.Build; -import androidx.annotation.RequiresApi; - -import java.util.concurrent.CompletableFuture; - -/** Utility class used to construct default {@link Material}s. */ -@RequiresApi(api = Build.VERSION_CODES.N) - -public final class MaterialFactory { - /** - * Name of material parameter for controlling the color of {@link #makeOpaqueWithColor(Context, - * Color)} and {@link #makeTransparentWithColor(Context, Color)} materials. - * - * @see Material#setFloat3(String, Color) - * @see Material#setFloat4(String, Color) - */ - public static final String MATERIAL_COLOR = "color"; - - /** - * Name of material parameter for controlling the texture of {@link - * #makeOpaqueWithTexture(Context, Texture)} and {@link #makeTransparentWithTexture(Context, - * Texture)} materials. - * - * @see Material#setTexture(String, Texture) - */ - public static final String MATERIAL_TEXTURE = "texture"; - - /** - * Name of material parameter for controlling the metallic property of all {@link MaterialFactory} - * materials. The metallic property defines whether the surface is a metallic (conductor) or a - * non-metallic (dielectric) surface. This property should be used as a binary value, set to - * either 0 or 1. Intermediate values are only truly useful to create transitions between - * different types of surfaces when using textures. The default value is 0. - * - * @see Material#setFloat(String, float) - */ - public static final String MATERIAL_METALLIC = "metallic"; - - /** - * Name of material parameter for controlling the roughness property of all {@link - * MaterialFactory} materials. The roughness property controls the perceived smoothness of the - * surface. When roughness is set to 0, the surface is perfectly smooth and highly glossy. The - * rougher a surface is, the “blurrier” the reflections are. The default value is 0.4. - * - * @see Material#setFloat(String, float) - */ - public static final String MATERIAL_ROUGHNESS = "roughness"; - - /** - * Name of material parameter for controlling the reflectance property of all {@link - * MaterialFactory} materials. The reflectance property only affects non-metallic surfaces. This - * property can be used to control the specular intensity. This value is defined between 0 and 1 - * and represents a remapping of a percentage of reflectance. The default value is 0.5. - * - * @see Material#setFloat(String, float) - */ - public static final String MATERIAL_REFLECTANCE = "reflectance"; - - private static final float DEFAULT_METALLIC_PROPERTY = 0.0f; - private static final float DEFAULT_ROUGHNESS_PROPERTY = 0.4f; - private static final float DEFAULT_REFLECTANCE_PROPERTY = 0.5f; - - /** - * Creates an opaque {@link Material} with the {@link Color} passed in. The {@link Color} can be - * modified by calling {@link Material#setFloat3(String, Color)} with {@link #MATERIAL_COLOR}. The - * metallicness, roughness, and reflectance can be modified using {@link Material#setFloat(String, - * float)}. - * - * @see #MATERIAL_METALLIC - * @see #MATERIAL_ROUGHNESS - * @see #MATERIAL_REFLECTANCE - * @param context a context used for loading the material resource - * @param color the color for the material to render - * @return material that will render the given color - */ - @SuppressWarnings("AndroidApiChecker") - // CompletableFuture requires api level 24 - public static CompletableFuture makeOpaqueWithColor(Context context, Color color) { - CompletableFuture materialFuture = - Material.builder() - .setSource( - context, - RenderingResources.GetSceneformResource( - context, RenderingResources.Resource.OPAQUE_COLORED_MATERIAL)) - .build(); - - return materialFuture.thenApply( - material -> { - material.setFloat3(MATERIAL_COLOR, color); - applyDefaultPbrParams(material); - return material; - }); - } - - /** - * Creates a transparent {@link Material} with the {@link Color} passed in. The {@link Color} can - * be modified by calling {@link Material#setFloat4(String, Color)} with {@link #MATERIAL_COLOR}. - * The metallicness, roughness, and reflectance can be modified using {@link - * Material#setFloat(String, float)}. - * - * @see #MATERIAL_METALLIC - * @see #MATERIAL_ROUGHNESS - * @see #MATERIAL_REFLECTANCE - * @param context a context used for loading the material resource - * @param color the color for the material to render - * @return material that will render the given color - */ - @SuppressWarnings("AndroidApiChecker") - // CompletableFuture requires api level 24 - public static CompletableFuture makeTransparentWithColor(Context context, Color color) { - CompletableFuture materialFuture = - Material.builder() - .setSource( - context, - RenderingResources.GetSceneformResource( - context, RenderingResources.Resource.TRANSPARENT_COLORED_MATERIAL)) - .build(); - - return materialFuture.thenApply( - material -> { - material.setFloat4(MATERIAL_COLOR, color); - applyDefaultPbrParams(material); - return material; - }); - } - - /** - * Creates an opaque {@link Material} with the {@link Texture} passed in. The {@link Texture} can - * be modified by calling {@link Material#setTexture(String, Texture)} with {@link - * #MATERIAL_TEXTURE}. The metallicness, roughness, and reflectance can be modified using {@link - * Material#setFloat(String, float)}. - * - * @see #MATERIAL_METALLIC - * @see #MATERIAL_ROUGHNESS - * @see #MATERIAL_REFLECTANCE - * @param context a context used for loading the material resource - * @param texture the texture for the material to render - * @return material that will render the given texture - */ - @SuppressWarnings("AndroidApiChecker") - // CompletableFuture requires api level 24 - public static CompletableFuture makeOpaqueWithTexture( - Context context, Texture texture) { - CompletableFuture materialFuture = - Material.builder() - .setSource( - context, - RenderingResources.GetSceneformResource( - context, RenderingResources.Resource.OPAQUE_TEXTURED_MATERIAL)) - .build(); - - return materialFuture.thenApply( - material -> { - material.setTexture(MATERIAL_TEXTURE, texture); - applyDefaultPbrParams(material); - return material; - }); - } - - /** - * Creates a transparent {@link Material} with the {@link Texture} passed in. The {@link Texture} - * can be modified by calling {@link Material#setTexture(String, Texture)} with {@link - * #MATERIAL_TEXTURE}. The metallicness, roughness, and reflectance can be modified using {@link - * Material#setFloat(String, float)}. - * - * @see #MATERIAL_METALLIC - * @see #MATERIAL_ROUGHNESS - * @see #MATERIAL_REFLECTANCE - * @param context a context used for loading the material resource - * @param texture the texture for the material to render - * @return material that will render the given texture - */ - @SuppressWarnings("AndroidApiChecker") - // CompletableFuture requires api level 24 - public static CompletableFuture makeTransparentWithTexture( - Context context, Texture texture) { - CompletableFuture materialFuture = - Material.builder() - .setSource( - context, - RenderingResources.GetSceneformResource( - context, RenderingResources.Resource.TRANSPARENT_TEXTURED_MATERIAL)) - .build(); - - return materialFuture.thenApply( - material -> { - material.setTexture(MATERIAL_TEXTURE, texture); - applyDefaultPbrParams(material); - return material; - }); - } - - private static void applyDefaultPbrParams(Material material) { - material.setFloat(MATERIAL_METALLIC, DEFAULT_METALLIC_PROPERTY); - material.setFloat(MATERIAL_ROUGHNESS, DEFAULT_ROUGHNESS_PROPERTY); - material.setFloat(MATERIAL_REFLECTANCE, DEFAULT_REFLECTANCE_PROPERTY); - } -} diff --git a/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.kt b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.kt new file mode 100644 index 0000000..1e8d23b --- /dev/null +++ b/sceneformsrc/sceneform/src/main/java/com/google/ar/sceneform/rendering/MaterialFactory.kt @@ -0,0 +1,170 @@ +package com.google.ar.sceneform.rendering + +import android.content.Context +import android.os.Build +import androidx.annotation.RequiresApi +import kotlinx.coroutines.future.await + +/** Utility class used to construct default {@link Material}s. */ +@RequiresApi(api = Build.VERSION_CODES.N) +object MaterialFactory { + + /** + * Name of material parameter for controlling the color of {@link #makeOpaqueWithColor(Context, + * Color)} and {@link #makeTransparentWithColor(Context, Color)} materials. + * + * @see Material#setFloat3(String, Color) + * @see Material#setFloat4(String, Color) + */ + const val MATERIAL_COLOR = "color" + + /** + * Name of material parameter for controlling the texture of {@link + * #makeOpaqueWithTexture(Context, Texture)} and {@link #makeTransparentWithTexture(Context, + * Texture)} materials. + * + * @see Material#setTexture(String, Texture) + */ + const val MATERIAL_TEXTURE = "texture" + + /** + * Name of material parameter for controlling the metallic property of all {@link MaterialFactory} + * materials. The metallic property defines whether the surface is a metallic (conductor) or a + * non-metallic (dielectric) surface. This property should be used as a binary value, set to + * either 0 or 1. Intermediate values are only truly useful to create transitions between + * different types of surfaces when using textures. The default value is 0. + * + * @see Material#setFloat(String, float) + */ + const val MATERIAL_METALLIC = "metallic" + + /** + * Name of material parameter for controlling the roughness property of all {@link + * MaterialFactory} materials. The roughness property controls the perceived smoothness of the + * surface. When roughness is set to 0, the surface is perfectly smooth and highly glossy. The + * rougher a surface is, the “blurrier” the reflections are. The default value is 0.4. + * + * @see Material#setFloat(String, float) + */ + const val MATERIAL_ROUGHNESS = "roughness" + + /** + * Name of material parameter for controlling the reflectance property of all {@link + * MaterialFactory} materials. The reflectance property only affects non-metallic surfaces. This + * property can be used to control the specular intensity. This value is defined between 0 and 1 + * and represents a remapping of a percentage of reflectance. The default value is 0.5. + * + * @see Material#setFloat(String, float) + */ + const val MATERIAL_REFLECTANCE = "reflectance" + + private const val DEFAULT_METALLIC_PROPERTY = 0.0f + private const val DEFAULT_ROUGHNESS_PROPERTY = 0.4f + private const val DEFAULT_REFLECTANCE_PROPERTY = 0.5f + + /** + * Creates an opaque {@link Material} with the {@link Color} passed in. The {@link Color} can be + * modified by calling {@link Material#setFloat3(String, Color)} with {@link #MATERIAL_COLOR}. The + * metallicness, roughness, and reflectance can be modified using {@link Material#setFloat(String, + * float)}. + * + * @see #MATERIAL_METALLIC + * @see #MATERIAL_ROUGHNESS + * @see #MATERIAL_REFLECTANCE + * @param context a context used for loading the material resource + * @param color the color for the material to render + * @return material that will render the given color + */ + suspend fun makeOpaqueWithColor(context: Context, color: Color): Material = + Material.builder() + .setSource( + context, + RenderingResources.GetSceneformResource( + context, RenderingResources.Resource.OPAQUE_COLORED_MATERIAL)) + .build() + .await().apply { + setFloat3(MATERIAL_COLOR, color) + applyDefaultPbrParams() + } + + /** + * Creates a transparent {@link Material} with the {@link Color} passed in. The {@link Color} can + * be modified by calling {@link Material#setFloat4(String, Color)} with {@link #MATERIAL_COLOR}. + * The metallicness, roughness, and reflectance can be modified using {@link + * Material#setFloat(String, float)}. + * + * @see #MATERIAL_METALLIC + * @see #MATERIAL_ROUGHNESS + * @see #MATERIAL_REFLECTANCE + * @param context a context used for loading the material resource + * @param color the color for the material to render + * @return material that will render the given color + */ + suspend fun makeTransparentWithColor(context: Context, color: Color): Material = + Material.builder() + .setSource( + context, + RenderingResources.GetSceneformResource( + context, RenderingResources.Resource.TRANSPARENT_COLORED_MATERIAL)) + .build() + .await().apply { + setFloat4(MATERIAL_COLOR, color) + applyDefaultPbrParams() + } + + /** + * Creates an opaque {@link Material} with the {@link Texture} passed in. The {@link Texture} can + * be modified by calling {@link Material#setTexture(String, Texture)} with {@link + * #MATERIAL_TEXTURE}. The metallicness, roughness, and reflectance can be modified using {@link + * Material#setFloat(String, float)}. + * + * @see #MATERIAL_METALLIC + * @see #MATERIAL_ROUGHNESS + * @see #MATERIAL_REFLECTANCE + * @param context a context used for loading the material resource + * @param texture the texture for the material to render + * @return material that will render the given texture + */ + suspend fun makeOpaqueWithTexture(context: Context, texture: Texture): Material = + Material.builder() + .setSource( + context, + RenderingResources.GetSceneformResource( + context, RenderingResources.Resource.OPAQUE_TEXTURED_MATERIAL)) + .build() + .await().apply { + setTexture(MATERIAL_TEXTURE, texture) + applyDefaultPbrParams() + } + + /** + * Creates a transparent {@link Material} with the {@link Texture} passed in. The {@link Texture} + * can be modified by calling {@link Material#setTexture(String, Texture)} with {@link + * #MATERIAL_TEXTURE}. The metallicness, roughness, and reflectance can be modified using {@link + * Material#setFloat(String, float)}. + * + * @see #MATERIAL_METALLIC + * @see #MATERIAL_ROUGHNESS + * @see #MATERIAL_REFLECTANCE + * @param context a context used for loading the material resource + * @param texture the texture for the material to render + * @return material that will render the given texture + */ + suspend fun makeTransparentWithTexture(context: Context, texture: Texture): Material = + Material.builder() + .setSource( + context, + RenderingResources.GetSceneformResource( + context, RenderingResources.Resource.TRANSPARENT_TEXTURED_MATERIAL)) + .build() + .await().apply { + setTexture(MATERIAL_TEXTURE, texture) + applyDefaultPbrParams() + } + + private fun Material.applyDefaultPbrParams() { + setFloat(MATERIAL_METALLIC, DEFAULT_METALLIC_PROPERTY) + setFloat(MATERIAL_ROUGHNESS, DEFAULT_ROUGHNESS_PROPERTY) + setFloat(MATERIAL_REFLECTANCE, DEFAULT_REFLECTANCE_PROPERTY) + } +} \ No newline at end of file